TCHAR数组的深层副本被截断

时间:2014-11-11 10:16:20

标签: c++ arrays unicode deep-copy tchar

我已经创建了一个类来测试我需要使用的一些功能。本质上,该类将获取传入的字符串的深层副本,并通过getter使其可用。我使用的是Visual Studio 2012.在项目设置中启用了Unicode。

问题是memcpy操作产生了截断的字符串。输出就是这样;

THISISATEST: InstanceDataConstructor: Testing testing 123
Testing te_READY

其中第一行是检查传入的TCHAR *字符串&第二行是使用memcpy操作填充分配的内存的输出。预期产量为; “测试测试123”。

有谁可以解释这里有什么问题?

N.B。从这里得到#ifndef UNICODE typedef: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

2 个答案:

答案 0 :(得分: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[]没什么不同。

答案 1 :(得分: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()的第三个参数是要复制的字节的计数。
如果字符串是存储在std::string中的简单ASCII字符串,则字节数与ASCII字符数相同。

但是,如果字符串是 wchar_t Unicode UTF-16 字符串,那么每个wchar_t在Visual C ++中占用 2个字节(带有GCC的东西是不同的,但这是用VC ++编译的Windows Win32 / C ++代码,所以我们只关注VC ++。) 因此,考虑到memcpy()的正确大小,您必须正确缩放wchar_t的大小计数,例如:

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

因此,如果您使用Unicode(UTF-16)模式进行编译,那么TCHAR将扩展为wchar_tsizeof(wchar_t)为2,因此原始字符串的内容应为正确地深度复制。

作为替代方案,对于VC ++中的Unicode UTF-16字符串,您也可以使用wmemcpy(),它将wchar_t视为&#34;副本单元&#34;。因此,在这种情况下,您不必将尺寸因子缩放sizeof(wchar_t)


作为旁注,在你的构造函数中你有:

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

由于strIn输入字符串参数,请考虑通过 const指针传递它,即:

InstanceData(const TCHAR* strIn)