3

I have code that works on Windows, but now that I am porting to a MAC, using Xcode 3.2.5 C/C++ Compiler Version GCC 4.2, it crashes.

I have narrowed it down to a memset call. If I comment out the memset it works, and if I put it back in the code crashes.

I have a structure that looks like this in my header file:

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;

Then in a cpp file I have this:

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

... later I have this:

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

Like I said before if I remove the memset call everything works fine. If I look at the debugger before I call the memset my strings in the structure are \0 and after the memset they are nil.

Why does the nil string crash on a assignment line and only on a MAC?

Thanks.

Michael Wildermuth
  • 5,762
  • 3
  • 29
  • 48
  • 2
    Just to elaborate on the answers… it crashes on the Mac (and likely any platform using GCC) because the internal state of `std::string` happens to be invalid when set to all NULL pointers. When a class contains a member with a non-trivial constructor (such as a constructor with an actual definition), its constructor is defined to zero out members with trivial constructors as well as calling the non-trivial constructors. So don't worry about `eTransportType`. Of course, the best way would be to name the nested type and define its constructor, thus avoiding `memset`. – Potatoswatter Jan 04 '12 at 02:01
  • 2
    When you break the rules, sometimes you get away with it and sometimes you don't. – David Schwartz Jan 04 '12 at 02:09

2 Answers2

14

You're overwriting deviceId's internal data by doing memset all over it; don't ever do memset over anything but a POD data type. This is C++, we have constructors. Your code should look something like this:

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];
};

Then

DeviceParams Param;

// get a pointer to Param in pParam

pParam->deviceNodes[index].deviceId = "some string";
Community
  • 1
  • 1
Seth Carnegie
  • 73,875
  • 22
  • 181
  • 249
11

It is illegal in C++ to call memset() on a non-POD data type. Structures containing std::string members are not POD.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285