2

I have a struct that looks like this:

typedef struct {
    int a;
    //other fields
    string s1;
    string s2;
} strMyStruct;

In The following code, append() method will crash since the string object x1.s1 was not constructed.

strMyStruct x1;
memset(&x1, 0, sizeof(x1));
x1.a = 100
x1.s1.append("....");

I can do placement new to solve it like new (x1.s1) string;, but it's too cumbersome and I don't have total control on the structure of strMyStruct: someone may add another string as a field to this struct and start using it and hit the crash issue, until he remembers to do placement new trick.

Really hoping the string class can handle it properly when initialization is done by memset(&x1, 0, sizeof(x1));. Is there a trick on this?

packetie
  • 4,839
  • 8
  • 37
  • 72
  • 4
    Why do you need to use `memset`? Why not use a normal constructor? The line `strMyStruct x1;` is already initializing the strings. – Apples May 22 '15 at 18:50
  • Didn't use constructor since I don't have the control on the structure, it keeps changing: Other developer may add/remove fields in this struct at will. Don't have a problem with initializing until people started using "string" object as a field. – packetie May 22 '15 at 18:53
  • @codingFun Your comment is the reason why using `memset` in a C++ program is dangerous. If other developers can update that struct, then you need to go over your code and remove / replace any calls to `memset`, `memcpy` etc. that is being done on that struct. – PaulMcKenzie May 22 '15 at 18:57
  • 1
    You don't generally need to `typedef` a `struct` in C++ (`struct` names are automatically a typename). [Difference between 'struct' and 'typedef struct' in C++?](http://stackoverflow.com/questions/612328/difference-between-struct-and-typedef-struct-in-c) – crashmstr May 22 '15 at 18:58
  • _`memset(&x1, 0, sizeof(x1));`_ Awwwww! – πάντα ῥεῖ May 22 '15 at 19:02
  • @PaulMcKenzie you are right. memset() is dangerous but it was acceptable before because all the numerical members of the struct should be initialized to be 0. `string` members changed all that :-( – packetie May 22 '15 at 19:02
  • 1
    @codingFun You can't use `memset()` to initialize complex objects :-P ... – πάντα ῥεῖ May 22 '15 at 19:03
  • 1
    @codingFun `but it was acceptable before` It should never have been acceptable, regardless of the member types in the struct. In C++, always use proper C++ initialization techniques, even if the struct or class contains POD (simple) types as members. – PaulMcKenzie May 22 '15 at 19:13

2 Answers2

6

You can use uniform initialization to default construct the object.

strMyStruct x1{};

This will default initialize the members of that object. The way you have it written, the variable is declared but not initialized. You can also use this syntax to value initialize your struct.

strMyStruct x2{5, "foo", "bar"};
Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
  • Thank you @CoryKramer, it works! SO prevents me from accepting it now, will do it in a few minutes. – packetie May 22 '15 at 18:58
  • 1
    It's worth noting that the second example here depends on the order of declaration of the struct members. If they are moved around, or if new members are added or removed, the initialization may silently break. – Apples May 22 '15 at 19:03
  • @DBRalir, good point. The job of my code is to make sure all members are initialized (numerical members are initialized to be 0, string members are initialized to be empty string). So `strMyStruct x1{};` will work for me in this case. – packetie May 22 '15 at 19:20
3
strMyStruct x1;

here x1.s1 is correctly constructed with empty string.

memset(&x1, 0, sizeof(x1));

at this place you have overwritten internal fields of x1.s1 - most probably seting to null pointer which was holding string buffer - but it depends on its implementation. You should be aware that using memset in such way is Undefined Behaviour - mostly casing crashes. But crash willnot happen here, at least yet.

x1.a = 100

thats fine

x1.s1.append("....");

and now you try to use x1.s1 which is in undefined state, this most probably will crash because internal data (pointer to memory buffer) is null. But you dont now, this might work - it depends on string implementation.

Finally your code can crash when x1.s1 will get destroyed.

You cannot use memset on non POD structures, and your struct is not such struct. So you are left with either using constructor for initializing your data, or universal initialization as in @CoryCramer answer.

marcinj
  • 48,511
  • 9
  • 79
  • 100