Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is a POD in a struct zero-initialized by an implicit constructor when creating an object in the heap or a temporary object in the stack?

The standard and the C++ book say that the default constructor for class type members is called by the implicit generated default constructor, but built-in types are not initialized. However, in this test program I get unexpected results when allocating an object in the heap or when using a temporary object:

#include<iostream>   struct Container {     int n; };  int main() {     Container c;     std::cout << "[STACK] Num: " << c.n << std::endl;      Container *pc = new Container();     std::cout << "[HEAP]  Num: " << pc->n << std::endl;     delete pc;      Container tc = Container();     std::cout << "[TEMP]  Num: " << tc.n << std::endl;  } 

I get this output:

[STACK] Num: -1079504552 [HEAP]  Num: 0 [TEMP]  Num: 0 

Is this some compiler specific behaviour? I don't really intend to rely on this, but I'm curious to know why this happens, specially for the third case.

like image 760
Jacobo de Vera Avatar asked Feb 08 '11 12:02

Jacobo de Vera


People also ask

Is struct initialized to 0?

z , it is initialized to a non-zero value because of the default member initializer provided. Using default member initializers (or other mechanisms that we'll cover later), structs and classes can self-initialize even when no explicit initializers are provided!

What is zero initialization in c++?

Zero Initialization in C++Setting the initial value of an object to zero is called the zero initialization.

Does unordered map initialize 0?

init]/6. So yes, your code is guaranteed to return 0…

Are class members initialized to zero?

If T is scalar (arithmetic, pointer, enum), it is initialized from 0 ; if it's a class type, all base classes and data members are zero-initialized; if it's an array, each element is zero-initialized.


1 Answers

It's expected behaviour. There are two concepts, "default initialization" and "value initialization". If you don't mention any initializer, the object is "default initialized", while if you do mention it, even as () for default constructor, the object is "value initialized". When constructor is defined, both cases call default constructor. But for built-in types, "value initialization" zeroes the memory whereas "default initialization" does not.

So when you initialize:

Type x; 

it will call default constructor if one is provided, but primitive types will be uninitialized. However when you mention an initializer, e.g.

Type x = {}; // only works for struct/class without constructor Type x = Type(); Type x{}; // C++11 only 

a primitive type (or primitive members of a structure) will be VALUE-initialized.

Similarly for:

struct X { int x; X(); }; 

if you define the constructor

X::X() {} 

the x member will be uninitialized, but if you define the constructor

X::X() : x() {} 

it will be VALUE-initialized. That applies to new as well, so

new int; 

should give you uninitialized memory, but

new int(); 

should give you memory initialized to zero. Unfortunately the syntax:

Type x(); 

is not allowed due to grammar ambiguity and

Type x = Type(); 

is obliged to call default constructor followed by copy-constructor if they are both specified and non-inlineable.

C++11 introduces new syntax,

Type x{}; 

which is usable for both cases. If you are still stuck with older standard, that's why there is Boost.ValueInitialized, so you can properly initialize instance of template argument.

More detailed discussion can be found e.g. in Boost.ValueInitialized documentation.

like image 88
Jan Hudec Avatar answered Oct 05 '22 14:10

Jan Hudec