views:

426

answers:

5

I have the following code:

struct B
{
 //B() {}
 int x;
 int y;
};

void print(const B &b) 
{
 std::cout<<"x:"<<b.x<<std::endl;
 std::cout<<"y:"<<b.y<<std::endl;
 std::cout<<"--------"<<std::endl;
}

int main()
{
 B b1 = B(); //init1
 B b2; //init2

 print(b1);
 print(b2);

 return 0;
}

When I start program (vs2008, debug) I have the following output:

x:0
y:0
--------
x:-858993460
y:-858993460
--------

As you can see b1.x and b1.y have 0 value. why? What's difference between init1 and init2?

When I uncomment B constructor I have the following output:

x:-858993460
y:-858993460
--------
x:-858993460
y:-858993460
--------

Can somebody explain the reason of this behaviour? Tnx in advance.

+10  A: 

Default constructor for POD types fills it with zeros. When you explicitly define your own constructor you are not initialize x and y and you'll get random values (in VS debug they are filled with exact values, but in release they will be random).

It is according to C++03 Standard 8.5/5:

<...>To value-initialize an object of type T means:
— if T is a class type (clause 9) with a user-declared constructor (12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
— 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;
— if T is an array type, then each element is value-initialized;
— otherwise, the object is zero-initialized.

B() is a value-initialization of temporary which will be used in copy-initialization of b1.

In B b2 there is no initializer specified for an object, so according to C++03 Standard 8.5/9:

If no initializer is specified for an object, and the object is of (possibly cv-qualified) non-POD class type (or array thereof), the object shall be default-initialized; if the object is of const-qualified type, the underlying class type shall have a user-declared default constructor. Otherwise, if no initializer is specified for a non-static object, the object and its subobjects, if any, have an indeterminate initial value; if the object or any of its subobjects are of const-qualified type, the program is ill-formed.

To get zeros for b2 you could write B b2 = {};.

Kirill V. Lyadvinsky
How does this explain the different results for `b1` and `b2`?
sth
And the last case for "default-initialize" should be "otherwise, no initialization is performed." This is the crucial difference here.
sth
@sth: No, default-initalize must zero-initialize other objects, the crucial point is that POD-types with automatic storage duration without an explicit initializer aren't even default-initialized.
Charles Bailey
@Charles: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2914.pdf says in 8.5/6 that no initialization is performed. That's the C++0x draft, so maybe it changed there, but I would be very surprised.
sth
VS2008 is a compile for the ISO 14882:2003 version of C++, so I think that this is the version of the standard that we should be looking at, not a draft for the next version.
Charles Bailey
@sth, added explanation of different results for `b1` and `b2`.
Kirill V. Lyadvinsky
isn't it just the value of whatever was in the relevant memory location last, not a random value? it's uninitialised, so it just uses whatever's already there !
Ed Woodcock
@Ed Woodcock, value is undefined by C++ Standard and since its location is random due to stack randomization (and undefined by C++ Standard), I call it random.
Kirill V. Lyadvinsky
Fair enough, I just wanted to be clear that it wasn't in fact random, although it may appear to be, otherwise we'd probably have some clever sod trying to make a random number generator based on undefined values :D Random != Undefined
Ed Woodcock
+2  A: 

The O's are explained by Kirill

The other value:-858993460 is 0xCCCCCCCC, which is the default value for uninitialized stack memory in VC's debug builds.

Uninitialized heap memory defaults to 0xCDCDCDCD. And of course, in release builds, the default contents is random.

Now, I have to admit that I didn't know it's legal to call a c'tor directly as you do in your example! And I would have sweared that this is illegal...

Serge - appTranslator
nitpicking: 0xCC is the default value for uninitialized **stack** memory in VC debug build. Uninitialized **heap** memory will contain 0xCD
sbk
A: 

i tried on vc6 and Visual Studio 2005 i am getting below result in both:Could you please post disassemble code generated , Like below i have posted disassemble code for 2005

x:-858993460

y:-858993460


x:-858993460

y:-858993460


 B b1 = B(); //init1
0043DEDE  lea         ecx,[b1] 
0043DEE1  call        B::B (43ADD9h) 
 B b2; //init2
0043DEE6  lea         ecx,[b2] 
0043DEE9  call        B::B (43ADD9h) 

 print(b1);
0043DEEE  lea         eax,[b1] 
0043DEF1  push        eax  
0043DEF2  call        print (43A302h) 
0043DEF7  add         esp,4 
 print(b2);
0043DEFA  lea         eax,[b2] 
0043DEFD  push        eax  
0043DEFE  call        print (43A302h) 
0043DF03  add         esp,4
sat
So, what's the reason of the difference? Assignment operators are out of the topic as they are not called. Destructors are also out of the topic. There is a lot of text in your post, but no clear answer.
Alex Che
@ Alex , thanks for comment, I assumed that opeator= was called, But after your comment i checked that it is not called at all, Let me do some testing , will reply soon :)
sat
+4  A: 

This is value-initialization versus no initialization. If you write

B b1 = B();

you get copy-initialization with a "value-initialized" temporary -- B(). Value-initialization of class-type objects invokes a user-defined constructor (if existant) or otherwise value-initializes the members. Value-initialization of scalar type objects is equivalent to zero-initialization. When you declare your own constructor that doesn't do anything, your scalar members are not initialized.

B b1;

is a default-initialization or no initialization at all (depending on B).

The exact initialization rules are rather complicated. See C++ standard section 8.5 "Initializers".

sellibitze
+4  A: 

In both cases, this statement defines b1 and copy-intializes it from a value-initialized temporary B object.

B b1 = B();

When B doesn't have a user-declared constructor, value-initializing causes call of B's members to be value-initalized, and for simple types, such as int, this means zero-initializing.

When B does have a user-declared constructor, value-initializing tries to call the default constructor. If the members x and y are not listed in the constructor initializer list, then they are left uninitialized.

B b2;

In functions, local objects of POD-type without an initializer are left uninitialized. When you don't define a constructor for B, it is a POD-class so this applies and the values of b2.x and b2.y have indeterminate values.

If the object is of non-POD class type, then it is default-initialized, but if this calls a constructor which leaves its members uninitialized then this makes no difference.

Charles Bailey
Do you mean that in the first case both copy and default constructors are called?
Alex Che
Nominally, yes, but the compiler is allowed to optimize out the copy. In this case it might directly _value-initialize_ `b1`. Whatever the compiler chooses to do, the observable effect (to the program) must be the same.
Charles Bailey
Thank you for the explanation.
Alex Che