tags:

views:

143

answers:

3

Let's say I have the following structure declaration (simple struct with no constructor).

struct Foo
{
    int x;
    int y;
    int z;
    char szData[DATA_SIZE];
};

Now let's say this struct is a member of a C++ class as follows:

class CFoobar
{
     Foo _foo;
public:
     CFoobar();
};

If I declare CFoobar's constructor as follows:

CFoobar::CFoobar()
{
    printf("_foo = {%d, %d, %d}\n", _foo.x, _foo.y,_foo.z);
    for (int x = 0; x < 100; x++)
       printf("%d\n", _foo.szData[x]);
}

As you would expect, when CFoobar's constructor runs, garbage data gets printed out Obviously, the easy fix is to memset or ZeroMemory &_foo. It's what I've always done...

However, I did notice that if add _foo to the constructor's initialization list with no parameters as follows:

CFoobar::CFoobar()
: _foo()
{

That this appears to zero-out the member variables of _foo. At least that was the case with g++ on linux.

Now here's my question: Is this standard C++, or is this compiler specific behavior?

If it's standard behavior, can someone quote me a reference from an official source? Any "gotchas" in regards to implicit zero-init behavior with more complicated structs and classes?

+6  A: 

Yes, this is defined behaviour according to the standard. 12.6.2 [class.base.init] / 3 : "if the expression-list of the mem-initializer is omitted, the base class or member subobject is value-initialized."

Be warned, though, if Foo wasn't a POD-type but still had no user-declared constructor (e.g. it had a std::string type) then some very popular compilers would not correctly value-initialize it.

All compilers that I know of do correctly perform value-initialization of POD members when you use () as the initializer in a constructor initializer-list.

Charles Bailey
"some popular compilers" = VC6 I assume? Because I haven't seen the wrong behavior in any compiler from the last 10 years.
MSalters
@MSalters: And VS2005 and VS2008 compilers, unfortunately. I haven't tried this on VS2010.
Charles Bailey
@MSalters: Not it only applies to non-POD struct members without a user-declared constructors; other types work correctly. There are several reports about this on Connect. This is one that I found: https://connect.microsoft.com/VisualStudio/feedback/details/484295/vc-does-not-value-initialize-members-of-derived-classes-without-user-declared-constructor
Charles Bailey
I meant "Note, it only applies...", not "Not it only..." but too late to edit. Also, even if VC6 is popular I'll point blank refuse to admit this fact. :)
Charles Bailey
Aha, there's at least one additional criterium (presence of base class). That might explain why I didn't notice.
MSalters
@MSalters: I've just run a test with no base class, just a member of non-POD struct type without a u-d constructor and the issue still occurs. E.g. this test case doesn't output "k.t.b = 0" as it should: `struct Test1 { std::string a; int b; }; struct Test2 { Test2() : t() {} Test1 t; }; int main() { Test2 k; std::cout << "k.t.b = " << k.t.b << std::endl; return 0; }` In debug it outputs the decimal value of `0xcccccccc` .
Charles Bailey
+1  A: 

i find it hard to read the standard, but I found it I think:

To value-initialize an object of type T means:
if T is a non-union class type without a user-declared constructor, then every non-static data member and base- class component of T is value-initialized Value-initialization for such a class object may be implemented by zero-initializing the object and then calling the default constructor.

Section 8.5

Chris H
8.5 needs to be read in conjunction with 12.6.2 to know that this member-initializer does indeed call for _value-initialization_ .
Charles Bailey
+1  A: 

It's the equivalent of float foo = float();

It will zero the object, even if the value representation is not all-bits-zero. I.e. it's even better than memset().

MSalters