Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing an object to all zeroes

Tags:

Oftentimes data structures' valid initialization is to set all members to zero. Even when programming in C++, one may need to interface with an external API for which this is the case.

Is there any practical difference between:

some_struct s; memset(&s, 0, sizeof(s)); 

and simply

some_struct s = { 0 }; 

Do folks find themselves using both, with a method for choosing which is more appropriate for a given application? (Hopefully it is understood that this is only currently applicable to POD structures; you'd get all sorts of havoc if there was a C++ std::string in that structure.)

For myself, as mostly a C++ programmer who doesn't use memset much, I'm never certain of the function signature so I find the second example is just easier to use in addition to being less typing, more compact, and maybe even more obvious since it says "this object is initialized to zero" right in the declaration rather than waiting for the next line of code and seeing, "oh, this object is zero initialized."

When creating classes and structs in C++ I tend to use initialization lists; I'm curious about folks thoughts on the two "C style" initializations above rather than a comparison against what is available in C++ since I suspect many of us interface with C libraries even if we code mostly in C++ ourselves.

Edit: Neil Butterworth posed this question, in followup, that I believe is an interesting corollary to this question.

like image 663
dash-tom-bang Avatar asked May 14 '10 21:05

dash-tom-bang


People also ask

How do you initialize structures to all elements zero or null?

Anything in C can be initialised with = 0 ; this initialises numeric elements to zero and pointers null.

Why do we initialize variables to zero?

In a language like Java, all variables *are* initialized to 0. That's because of Java's insistence on safety.

Does C++ initialize variables to zero?

Unlike some programming languages, C/C++ does not initialize most variables to a given value (such as zero) automatically. Thus when a variable is assigned a memory location by the compiler, the default value of that variable is whatever (garbage) value happens to already be in that memory location!


1 Answers

memset is practically never the right way to do it. And yes, there is a practical difference (see below).

In C++ not everything can be initialized with literal 0 (objects of enum types can't be), which is why in C++ the common idiom is

some_struct s = {}; 

while in C the idiom is

some_struct s = { 0 }; 

Note, that in C the = { 0 } is what can be called the universal zero initializer. It can be used with objects of virtually any type, since the {}-enclosed initializers are allowed with scalar objects as well

int x = { 0 }; /* legal in C (and in C++) */ 

which makes the = { 0 } useful in generic type-independent C code (type-independent macros for example).

The drawback of = { 0 } initializer in C89/90 and C++ is that it can only be used as a part of declaration. (C99 fixed this problem by introducing compound literals. Similar functionality is coming to C++ as well.) For this reason you might see many programmers use memset in order to zero something out in the middle of C89/90 or C++ the code. Yet, I'd say that the proper way to do is still without memset but rather with something like

some_struct s; ... {   const some_struct ZERO = { 0 };     s = ZERO; } ... 

i.e. by introducing a "fictive" block in the middle of the code, even though it might not look too pretty at the first sight. Of course, in C++ there's no need to introduce a block.

As for the practical difference... You might hear some people say that memset will produce the same results in practice, since in practice the physical all-zero bit pattern is what is used to represent zero values for all types. However, this is generally not true. An immediate example that would demonstrate the difference in a typical C++ implementation is a pointer-to-data-member type

struct S; ...  int S::*p = { 0 }; assert(p == NULL); // this assertion is guaranteed to hold  memset(&p, 0, sizeof p); assert(p == NULL); // this assertion will normally fail 

This happens because a typical implementation usually uses the all-one bit pattern (0xFFFF...) to represent the null pointer of this type. The above example demonstrates a real-life practical difference between a zeroing memset and a normal = { 0 } initializer.

like image 129
AnT Avatar answered Oct 27 '22 18:10

AnT