s.matushonok
s.matushonok

Reputation: 7585

Two ways of calling default constructor

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.

Upvotes: 5

Views: 6358

Answers (5)

Serge Wautier
Serge Wautier

Reputation: 21898

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...

Upvotes: 2

Satbir
Satbir

Reputation: 6516

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 

Upvotes: 0

Kirill V. Lyadvinsky
Kirill V. Lyadvinsky

Reputation: 99725

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 = {};.

Upvotes: 10

CB Bailey
CB Bailey

Reputation: 793299

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.

Upvotes: 5

sellibitze
sellibitze

Reputation: 28127

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".

Upvotes: 3

Related Questions