2014-11-11 2 views
1

Я создал класс для проверки некоторой функциональности, которую мне нужно использовать. По сути, класс возьмет глубокую копию переданной строки и сделает ее доступной через геттер. Я использую Visual Studio 2012. Unicode включен в настройках проекта.Глубокая копия массива TCHAR усечена

Проблема заключается в том, что операция memcpy дает усеченную строку. Результат такой же;

THISISATEST: InstanceDataConstructor: Testing testing 123 
Testing te_READY 

где первая линия является проверка прошла в TCHAR * строка & вторая линия является выходом из заполнения выделенной памяти с операцией тетсру. Ожидаемый результат; «Тестирование тестирования 123».

Может кто-нибудь объяснить, что здесь не так?

N.B. Получил #ifndef UNICODE определений типов отсюда: how-to-convert-tchar-array-to-stdstring

#ifndef INSTANCE_DATA_H//if not defined already 
#define INSTANCE_DATA_H//then define it 

#include <string> 

//TCHAR is just a typedef, that depending on your compilation configuration, either defaults to char or wchar. 
//Standard Template Library supports both ASCII (with std::string) and wide character sets (with std::wstring). 
//All you need to do is to typedef String as either std::string or std::wstring depending on your compilation configuration. 
//To maintain flexibility you can use the following code: 
#ifndef UNICODE 
    typedef std::string String; 
#else 
    typedef std::wstring String; 
#endif 
//Now you may use String in your code and let the compiler handle the nasty parts. String will now have constructors that lets you convert TCHAR to std::string or std::wstring. 


class InstanceData 
{ 
public: 
    InstanceData(TCHAR* strIn) : strMessage(strIn)//constructor  
     { 
     //Check to passed in string 
     String outMsg(L"THISISATEST: InstanceDataConstructor: ");//L for wide character string literal 
     outMsg += strMessage;//concatenate message 
     const wchar_t* finalMsg = outMsg.c_str();//prepare for outputting 
     OutputDebugStringW(finalMsg);//print the message  

     //Prepare TCHAR dynamic array. Deep copy. 
     charArrayPtr = new TCHAR[strMessage.size() +1]; 
     charArrayPtr[strMessage.size()] = 0;//null terminate 
     std::memcpy(charArrayPtr, strMessage.data(), strMessage.size());//copy characters from array pointed to by the passed in TCHAR*. 

     OutputDebugStringW(charArrayPtr);//print the copied message to check  
     } 

    ~InstanceData()//destructor 
     { 
      delete[] charArrayPtr; 
     } 

//Getter 
TCHAR* getMessage() const 
{ 
    return charArrayPtr; 
} 

private: 
    TCHAR* charArrayPtr; 
    String strMessage;//is used to conveniently ascertain the length of the passed in underlying TCHAR array. 
}; 
#endif//header guard 
+0

используйте 'String' вместо' TCHAR * 'для' charArrayPtr' –

+4

ваш 'memcpy' слишком короткий, третий аргумент shoudl - количество байтов, но вы передаете количество символов. Используйте 'std :: copy' isntead. –

+2

Или, может быть, 'std :: memcpy (charArrayPtr, strMessage.data(), strMessage.size() * sizeof (TCHAR))' –

ответ

1

Пожалуйста, обратите внимание на следующие строки в коде:

// Prepare TCHAR dynamic array. Deep copy. 
charArrayPtr = new TCHAR[strMessage.size() + 1]; 
charArrayPtr[strMessage.size()] = 0; // null terminate 

// Copy characters from array pointed to by the passed in TCHAR*. 
std::memcpy(charArrayPtr, strMessage.data(), strMessage.size()); 

Третий аргумент для передачи memcpy() является счетчиком байтов скопировать.
Если строка представляет собой простую строку ASCII, хранящуюся в std::string, то количество байтов совпадает с количеством символов ASCII.

Но, если строка является wchar_t Unicode UTF-16 строка, то каждый wchar_t занимает 2 байта в Visual C++ (с GCC вещи разные, но это код для Windows Win32/C++ компилируется с VC++ , поэтому давайте просто сосредоточимся на VC++).
Таким образом, вы должны правильно масштабировать количество размера для memcpy(), учитывая правильный размер wchar_t, например:

memcpy(charArrayPtr, strMessage.data(), strMessage.size() * sizeof(TCHAR)); 

Так что, если вы собираете в Unicode режим (UTF-16), а затем TCHAR расширяется до wchar_t и sizeof(wchar_t) равно 2, поэтому содержимое исходной строки должно быть правильно скопировано.

В качестве альтернативы для строк Unicode UTF-16 в VC++ вы также можете использовать wmemcpy(), который считает wchar_t своей «единицей копии». Таким образом, в этом случае вам не нужно масштабировать размерный коэффициент на sizeof(wchar_t).


В качестве примечания, в конструкторе у вас есть:

InstanceData(TCHAR* strIn) : strMessage(strIn)//constructor  

Поскольку strIn является входной параметр строка, рассмотреть вопрос о принятии его const указатель, а именно:

InstanceData(const TCHAR* strIn) 
2

решение без всех динамически распределяемой памяти.

#include <tchar.h> 
#include <vector> 
//... 
class InstanceData 
{ 
    public: 
     InstanceData(TCHAR* strIn) : strMessage(strIn), 
     { 
      charArrayPtr.insert(charArrayPtr.begin(), strMessage.begin(), strMessage.end()) 
      charArrayPtr.push_back(0); 
     } 

     TCHAR* getMessage() 
     { return &charArrayPtr[0]; } 

    private: 
     String strMessage; 
     std::vector<TCHAR> charArrayPtr; 
}; 

Это делает то, что делает ваш класс, но главное отличие в том, что он не делает каких-либо скрученные вручную динамический код распределения. Класс также безопасно скопируется, в отличие от кода с динамическим распределением (отсутствует пользовательский конструктор копирования и оператор присваивания).

Класс std::vector заменен, необходимо сделать new[]/delete[] практически во всех случаях. Причина в том, что vector сохраняет свои данные в непрерывной памяти, не говоря уже о вызове new[].

Смежные вопросы