Почему MFC C++ CString (const char*) полностью меняет значение const char*?

Я надеюсь, что название было достаточно хорошим, чтобы помочь объяснить, с чем у меня проблемы. Я думаю, что как только я решу эту проблему, мой проект будет в значительной степени завершен. На заметку, оба проекта скомпилированы под Unicode.

Я работаю с CLI/C++ DLL, которая принимает LPCTSTR и возвращает const char*. Если я сохраняю значение возврата в const char* в моем проекте при прохождении, я вижу, что возвращаемое значение - это то, что я ожидаю вернуть.

Теперь, если я сделаю следующее:

LPCTSTR strValue = L"test";
const char* Return = MethodCall(strValue);
LPCTSTR Final = CString(Return);

Возврат будет равен "Xmkk=Asmks" (что и должно быть). Этот метод шифрует строку. Проблема в том, что когда я делаю CString, Final будет равно «ﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮ㹙癞鞮᠀諸²⤐²». Как мне превратить onst char* в LPCTSTR без изменения его данных"

Спасибо.


person Landin Martens    schedule 20.03.2012    source источник
comment
Не можете ли вы изменить C++/CLI DLL? Вам действительно не следует хранить строки в массиве char в приложении Unicode. Используйте wchar_t (или TCHAR).   -  person Cody Gray    schedule 20.03.2012
comment
@CodyGray Или CStringA, который является 8-битной CString, независимо от того, определен ли Unicode.   -  person Mr Lister    schedule 20.03.2012


Ответы (3)


После уничтожения CString(Return) (это происходит "прямо на следующей строке после его построения") "Final" указатель указывает на освобожденный кусок памяти (который был внутренним буфером CString(Return)). На данный момент содержимое памяти, на которое он указывает, не определено, и разыменование его является неопределенным поведением.
Чтобы безопасно использовать указатель на внутренний буфер, вы должны убедиться, что CString, которой принадлежит буфер, жив, пока указатель существует.


LPCTSTR strValue = L"test";
const char* Return = MethodCall(strValue);
LPCTSTR PointerToBuffer= 0;
{
  CString ReturnStringObj(Return);
  PointerToBuffer = ReturnStringObj;  
  // Can safelly use your pointer here  
}
// Here ReturnStringObj is killed and pointer dereferencing is invalid here




person cybevnm    schedule 20.03.2012
comment
Метод возвращает Final, так что мне делать, чтобы решить мою проблему. Я до сих пор учусь. - person Landin Martens; 20.03.2012
comment
@ user1078510: может быть LPCTSTR Final = _tcsdup(CString(Return));. Не забудьте free(Final) в какой-то момент. - person Michael Burr; 20.03.2012
comment
Это зависит... Как долго указатель возврата будет указывать на допустимую память после MethodCall и т. д. Вы можете просто хранить где-нибудь всю CString (как член класса и т. д.), или вы можете использовать std::wstring. Это зависит в основном от вашего дизайна - person cybevnm; 20.03.2012

Как упоминает vnm, вы создаете временный объект CString, вызывая его конструктор в строке 3, а затем этот объект немедленно уничтожается. Это освобождает часть памяти, которую он использовал для вашего буфера, а это означает, что любые попытки доступа к данным, хранящимся в этой памяти, будут иметь неопределенное поведение. Вот почему ваша строка выглядит искаженной: она уже удалена.

Если вы новичок в C++, вам нужно убедиться, что вы понимаете время жизни объекта. Это сделало бы написание этого кода значительно проще.

Решение состоит в том, чтобы гарантировать, что ваш объект CString не будет уничтожен, пока вы не закончите с ним работать. Если вам нужно, чтобы объект существовал только внутри вашей функции, вы можете оставить его как временный объект, созданный внутри этой функции. Если вам нужно, чтобы он существовал вне этой функции, вам нужно создать его на более высоком уровне или сохранить указатель на него.

Обратите внимание, что объекты CString неявно преобразуются в LPCTSTR.

Итак, предполагая, что вам нужен только объект CString, чтобы оставаться в рамках вашей функции, вы можете написать следующий код:

{
    // Declare a string literal
    LPCTSTR strValue = L"test";

    // Encrypt the string
    const char* strReturn = MethodCall(strValue);

    // Create a CString object representing the encrypted string
    CStringA myString(strReturn);

    // Do something with myString, like display it in a message box
    // (Remember that it's an ANSI (non-Unicode) string!)
    // ...
    MessageBoxA(NULL, myString, NULL, MB_OK);
    // ...

    // myString (your CString object) gets destroyed here
}
person Cody Gray    schedule 20.03.2012

Что вы можете сделать, так это создать новый объект CStringA и преобразовать его в const char* для Final. Тогда Final останется действительным, пока определен CStringA.

Я бы не рекомендовал использовать CString (или CStringW) для хранения, доступ к которому вам потребуется с помощью const char*.

person Mr Lister    schedule 20.03.2012