Строка C для широкого назначения строки C

Я немного запутался в C-струнах и широких C-струнах. Ради этого вопроса предположим, что я использую Microsoft Visual Studio 2010 Professional. Пожалуйста, дайте мне знать, если какая-либо из моих данных неверна.

У меня есть структура с константным членом wchar_t *, который используется для хранения имени.

struct A
{
const wchar_t* name;
};

Когда я назначаю объекту ‘a’ имя так:

int main()
{
A a;

const wchar_t* w_name = L"Tom";
a.name = w_name;

return 0;
}

Это просто копирование адреса памяти, на который указывает w_name, в a.name. Теперь w_name и a.name являются указателями широких символов, которые указывают на один и тот же адрес в памяти.

Если я прав, то мне интересно, что делать с такой ситуацией. Я читаю в строке C из атрибута XML, используя tinyxml2.

tinyxml2::XMLElement* pElement;
// ...
const char* name = pElement->Attribute("name");

Получив строку C, я преобразую ее в строку широких символов следующим образом:

size_t newsize = strlen(name) + 1;
wchar_t * wcName = new wchar_t[newsize];
size_t convertedChars = 0;
mbstowcs_s(&convertedChars, wcName, newsize, name, _TRUNCATE);

a.name = wcName;

delete[] wcName;

Если я пока прав, то строка:

 a.name = wcName;

просто копирует адрес памяти первого символа массива wcName в a.name. Тем не менее, я удаляю wcName сразу после назначения этого указателя, что делает его указателем на мусор.

Как я могу преобразовать мою строку C в строку C широких символов и затем присвоить ее a.name?

1

Решение

Самый простой подход — это, вероятно, поручить вам name переменная с управлением памятью. Это, в свою очередь, легко сделать, объявив его

std::wstring name;

У этих ребят нет концепции независимого контента и мутаций объектов, то есть вы не можете создать отдельных персонажей. const и делает весь объект const будет препятствовать тому, чтобы это было назначено.

3

Другие решения

Вы Можно сделать это, используя std::wstring не полагаясь на дополнительное временное преобразование буфера выделения и уничтожения. Не очень важно, если вы явно не обеспокоены фрагментацией кучи или в ограниченной системе (например, Windows Phone). Это займет немного настройки на лицевой стороне. Позвольте стандартной библиотеке управлять памятью для вас (с небольшим толчком).

class A
{
...
std::wstring a;
};// Convert the string (I'm assuming it is UTF8) to wide char
int wlen = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, NULL);
if (wlen > 0)
{
// reserve space. std::wstring gives us the terminator slot
// for free, so don't include that. MB2WC above returns the
// length *including* the terminator.
a.resize(wlen-1);
MultiByteToWideChar(CP_UTF8, 0, name, -1, &a[0], wlen);
}
else
{   // no conversion available/possible.
a.clear();
}

С полной стороны, вы Можно собрать TinyXML для использования стандартной библиотеки и std::string скорее, чем char *, который на самом деле не очень вам помогает, но может спасти вас тонна будущего strlen() звонит позже.

1

Как вы правильно упомянули a.name это просто указатель, который не предполагает выделенного хранилища строк. Вы должны управлять им вручную, используя new или статический / ограниченный массив.

Чтобы избавиться от этих скучных вещей, просто используйте один из доступных классов строк: CStringW из ATL (простой в использовании, но специфичный для MS) или std::wstring из STL (стандарт C ++, но не так легко конвертировать из char*):

#include <atlstr.h>

// Conversion ANSI -> Wide is automatic
const CStringW name(pElement->Attribute("name"));

К несчастью, std::wstring использование с char* это не так просто.
Смотрите функцию преобразования здесь: Как преобразовать std :: string в LPCWSTR в C ++ (Unicode)

0
По вопросам рекламы [email protected]