Как освободить память после преобразования управляемой строки в неуправляемый символ * в кодировке UTF-8? - PullRequest
1 голос
/ 14 декабря 2011

Я не знаком с C ++ / CLI, поэтому не уверен, как освободить память при использовании кода ниже (получил решение здесь и немного изменил):

char* ManagedStringToUnmanagedUTF8Char( String^ s )
{
    array<unsigned char> ^bytes = Encoding::UTF8->GetBytes( s );
    pin_ptr<unsigned char> pinnedPtr = &bytes[0];
    return (char*)pinnedPtr;
}

Приведенный выше код работает, когда я тестировал его, записывая char в текстовый файл.Пожалуйста, дайте мне знать, если я что-то упустил (нужно очистить pinnedPtr?).

Теперь, когда я его использую:

char* foobar = ManagedStringToUnmanagedUTF8Char("testing");

//do something with foobar

//do I need to free up memory by deleting foobar here? 
//I tried 'delete foobar' or free(foobar) but it crashes my program

Ответы [ 2 ]

0 голосов
/ 16 декабря 2011

Комментарий Ханса Пассанта верен, что возвращенный указатель на буфер может быть перемещен в память сборщиком мусора. Это потому, что когда стек функций раскручивается, pin_ptr открепит указатель.

Решение для

  1. Получите буфер System :: String и закрепите его так, чтобы ГХ не мог подвинь это.
  2. Выделите память в неуправляемой куче (или просто куче), где он не находится под юрисдикцией GC и не может быть перемещен GC.
  3. Копирование памяти (и преобразование в нужную кодировку) из System :: String буфер к буферу, расположенному в неуправляемой куче.
  4. Открепить указатель, чтобы ГХ мог снова переместить System :: String в памяти. (Это делается, когда pin_ptr выходит из функции Объем.)

Пример кода:

char* ManagedStringToUnmanagedUTF8Char(String^ str)
{
    // obtain the buffer from System::String and pin it
    pin_ptr<const wchar_t> wch = PtrToStringChars(str);

    // get number of bytes required
    int nBytes = ::WideCharToMultiByte(CP_UTF8, NULL, wch, -1, NULL, 0, NULL, NULL);
    assert(nBytes >= 0);

    // allocate memory in C++ where GC cannot move
    char* lpszBuffer = new char[nBytes];

    // initialize buffer to null
    ZeroMemory(lpszBuffer, (nBytes) * sizeof(char)); 

    // Convert wchar_t* to char*, specify UTF-8 encoding
    nBytes = ::WideCharToMultiByte(CP_UTF8, NULL, wch, -1, lpszBuffer, nBytes, NULL, NULL);
    assert(nBytes >= 0);

    // return the buffer
    return lpszBuffer;
}

Теперь при использовании:

char* foobar = ManagedStringToUnmanagedUTF8Char("testing");

//do something with foobar

//when foobar is no longer needed, you need to delete it
//because ManagedStringToUnmanagedUTF8Char has allocated it on the unmanaged heap.
delete foobar;
0 голосов
/ 14 декабря 2011

Я тоже не знаком с Visual-C ++, но, согласно этой статье

Указатели закрепления нельзя использовать в качестве: [...] возвращаемого типа функции

Я не уверен, будет ли указатель действительным после завершения функции (даже если он замаскирован под char*. Кажется, вы объявляете в функции некоторые локальные переменные, которые хотите передать в область вызова. «Однако, возможно, они все равно выйдут из области видимости, когда вы вернетесь из функции. Может быть, вы должны пересмотреть то, что вы пытаетесь достичь в первую очередь?

Обратите внимание, что в статье, на которую вы ссылались, std::string (передается по значению, т.е. по копии) используется в качестве возвращаемого параметра.

std::string managedStringToStlString( System::String ^s )
{
  Encoding ^u8 = Encoding::UTF8;
  array<unsigned char> ^bytes = u8->GetBytes( s );
  pin_ptr<unsigned char> pinnedPtr = &bytes[0];
  return string( (char*)pinnedPtr );
}

Таким образом, локальные переменные не выходят за пределы своей области видимости. Строка обрабатывается копией как неуправляемый std::string. Это именно то, что предлагает этот пост .

Когда вам понадобится const char* позже, вы можете использовать метод string :: c_str () , чтобы получить его. Обратите внимание, что вы также можете записать std::string в файл, используя file streams . Это вариант для вас?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...