memset在std::string赋值时导致崩溃

3
我有一段在Windows上正常工作的代码,但现在我要将其移植到MAC上,使用的是Xcode 3.2.5 C/C++编译器版本GCC 4.2,结果它会崩溃。
经过分析,我发现问题出现在一个memset调用中。如果我把memset注释掉,代码就能正常运行;但如果重新加入这个语句,代码又会崩溃。
在我的头文件中,有一个结构体,长这样:
typedef struct 
{
    int deviceCount;
    struct 
    {
        #define MAX_DEVICE_ID 256
        #define MAX_DEVICE_ENTRIES 10
        std::string deviceId;   // Device name to Open
        TransportType   eTransportType;
    } deviceNodes[MAX_DEVICE_ENTRIES];
} DeviceParams;

然后在一个cpp文件中我有这样:

DeviceParams Param;
memset(&Param, nil, sizeof(Param));

稍后我有这个:

... 稍后我将拥有这个:

pParam->deviceNodes[index].deviceId = "some string"; // <----- Line that crashes with memset

就像我之前所说的,如果我删除memset调用,一切都能很好地工作。如果在调用memset之前查看调试器,我的结构中的字符串是\0,在memset之后它们变成了nil。

为什么nil字符串在赋值行上崩溃,而且只在MAC上呢?

谢谢。


2
只是为了详细说明答案...它在Mac上崩溃(以及可能使用GCC的任何平台),因为当设置为所有NULL指针时,std::string的内部状态恰好无效。当一个类包含一个具有非平凡构造函数(例如具有实际定义的构造函数)的成员时,它的构造函数被定义为将具有平凡构造函数的成员清零并调用非平凡构造函数。所以不要担心eTransportType。当然,最好的方法是命名嵌套类型并定义其构造函数,从而避免memset - Potatoswatter
2
当你违反规则时,有时候你能逃脱惩罚,有时候却不行。 - David Schwartz
2个回答

14

你正在通过 memset 覆盖 deviceId 的内部数据;除了POD 数据类型,不要对任何东西进行 memset。这是 C++,我们有构造函数。你的代码应该像这样:

struct DeviceParams
{
    int deviceCount;

    struct DeviceNode
    {
        DeviceNode() : eTransportType() { } // initialise eTransportType
                                            // to 0, deviceId initialises itself

        static const int MAX_DEVICE_ID = 256;
        static const int MAX_DEVICE_ENTRIES = 10;

        std::string deviceId; // Device name to Open
        TransportType eTransportType;
    } deviceNodes[DeviceNode::MAX_DEVICE_ENTRIES];
};

接着

DeviceParams Param;

// get a pointer to Param in pParam

pParam->deviceNodes[index].deviceId = "some string";

11

C++ 中在非 POD 数据类型上调用 memset() 是不合法的。包含 std::string 成员的结构体不是 POD。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接