Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this C++ structure initialization trick safe?

Instead of having to remember to initialize a simple 'C' structure, I might derive from it and zero it in the constructor like this:

struct MY_STRUCT {     int n1;     int n2; };  class CMyStruct : public MY_STRUCT { public:     CMyStruct()     {         memset(this, 0, sizeof(MY_STRUCT));     } }; 

This trick is often used to initialize Win32 structures and can sometimes set the ubiquitous cbSize member.

Now, as long as there isn't a virtual function table for the memset call to destroy, is this a safe practice?

like image 991
Rob Avatar asked Sep 21 '08 20:09

Rob


People also ask

What is the problem of initialization?

Problem of initialization in C++ Therefore, when objects are created, the members of the object cannot be initialized directly and this problem of not being able to initialize data members is known as the problem of initialization.

What is structure initialization in C?

An initializer for a structure is a brace-enclosed comma-separated list of values, and for a union, a brace-enclosed single value. The initializer is preceded by an equal sign ( = ).

Can we initialize variable in structure in C?

Structure members cannot be initialized with declaration.

Is it possible to initialize structure members during structure definition?

Que: Can we initialize structure members within structure definition? No! We cannot initialize a structure members with its declaration, consider the given code (that is incorrect and compiler generates error).


2 Answers

You can simply value-initialize the base, and all its members will be zero'ed out. This is guaranteed

struct MY_STRUCT {     int n1;     int n2; };  class CMyStruct : public MY_STRUCT { public:     CMyStruct():MY_STRUCT() { } }; 

For this to work, there should be no user declared constructor in the base class, like in your example.

No nasty memset for that. It's not guaranteed that memset works in your code, even though it should work in practice.

like image 55
Johannes Schaub - litb Avatar answered Sep 19 '22 13:09

Johannes Schaub - litb


PREAMBLE:

While my answer is still Ok, I find litb's answer quite superior to mine because:

  1. It teaches me a trick that I did not know (litb's answers usually have this effect, but this is the first time I write it down)
  2. It answers exactly the question (that is, initializing the original struct's part to zero)

So please, consider litb's answer before mine. In fact, I suggest the question's author to consider litb's answer as the right one.

Original answer

Putting a true object (i.e. std::string) etc. inside will break, because the true object will be initialized before the memset, and then, overwritten by zeroes.

Using the initialization list doesn't work for g++ (I'm surprised...). Initialize it instead in the CMyStruct constructor body. It will be C++ friendly:

class CMyStruct : public MY_STRUCT { public:     CMyStruct() { n1 = 0 ; n2 = 0 ; } }; 

P.S.: I assumed you did have no control over MY_STRUCT, of course. With control, you would have added the constructor directly inside MY_STRUCT and forgotten about inheritance. Note that you can add non-virtual methods to a C-like struct, and still have it behave as a struct.

EDIT: Added missing parenthesis, after Lou Franco's comment. Thanks!

EDIT 2 : I tried the code on g++, and for some reason, using the initialization list does not work. I corrected the code using the body constructor. The solution is still valid, though.

Please reevaluate my post, as the original code was changed (see changelog for more info).

EDIT 3 : After reading Rob's comment, I guess he has a point worthy of discussion: "Agreed, but this could be an enormous Win32 structure which may change with a new SDK, so a memset is future proof."

I disagree: Knowing Microsoft, it won't change because of their need for perfect backward compatibility. They will create instead an extended MY_STRUCTEx struct with the same initial layout as MY_STRUCT, with additionnal members at the end, and recognizable through a "size" member variable like the struct used for a RegisterWindow, IIRC.

So the only valid point remaining from Rob's comment is the "enormous" struct. In this case, perhaps a memset is more convenient, but you will have to make MY_STRUCT a variable member of CMyStruct instead of inheriting from it.

I see another hack, but I guess this would break because of possible struct alignment problem.

EDIT 4: Please take a look at Frank Krueger's solution. I can't promise it's portable (I guess it is), but it is still interesting from a technical viewpoint because it shows one case where, in C++, the "this" pointer "address" moves from its base class to its inherited class.

like image 40
paercebal Avatar answered Sep 18 '22 13:09

paercebal