Constructors and initialization
Default Initialization with default constructor
struct MyObject
{
int a;
unsigned long b;
unsigned long b2;
void* c;
MyObject(void) = default;
};
int main(void)
{
MyObject obj;
return 0;
}
-
The stack object does not have an explicit defined constructor. On the contrary, the constructor is explicitly defaulted, but is (I think) syntax sugar.
-
We are not calling the constructor, so the object is default initialized.
-
Despite of this, the objet members are in a undetermined state.
Default initialization is the initialization that occurs when no other initialization is specified; the C++ language guarantees you that any object for which you do not provide an explicit initializer will be default initialized (C++11 §8.5/11).
However, there are types for which default initialization has no effect and leaves the object's value indeterminate: any non-class, non-array type (§8.5/6). Consequently, a default-initialized array of objects with such types will have indeterminate value, e.g.:
int plain_int;
int c_style_array[13];
std::array<int, 13> cxx_style_array;
Both the c-style array and std::array are filled with integers of indeterminate value, just as plain_int has indeterminate value.
Default Initialization with non-default constructor
struct MyObject
{
int a;
unsigned long b;
void* c;
MyObject() :
a(0),
b('\0'),
c(nullptr)
{
puts("Called ctor");
}
};
int main(void)
{
MyObject obj;
return 0;
}
-
The stack object has an explicit defined constructor.
-
We are not calling the constructor, so the object default initialized.
-
Since we are provided a constructor, that constructor is called.
-
The constructor sets the member to a well-known zero state.
Value Initialization with default constructor
struct MyObject
{
int a;
unsigned long b;
unsigned long b2;
void* c;
MyObject(void) = default;
};
int main(void)
{
MyObject obj{};
return 0;
}
- We explicitly require value-initialization for the object using the
obj{}
syntax. As a result, its member of built-in POD types are initialized to the zero default value.
You can request value initialization quite easily in C++11 by giving each declaration an empty initializer:
int plain_int{};
int c_style_array[13]{};
std::array<int, 13> cxx_style_array{};
Which will value-initialize all of the array elements in turn, resulting in plain_int, and all the members of both kinds of arrays, being initialized to zero.
When declaring an object with an explicit default constructor, and the class has only POD types, and the object is declared on the stack / heap, then we need to explicitly value-intialize members to make sure they are zeroed.
However, if the class has a constructor (with or without member initializer
list like NonDefault
), then those members are always set to the values
defined in the constructor.
Some more details:
-
for the default-constructor case, there is no constructor symbol
MyObject::MyObject
generated by the compiler. As a consequence the compiler doesn't do any initialization at all if you don't ask it. A symbol is generated if at least a member has a more complex class type, calling the ctor for that member. However the POD types are still left to an undetermined state. -
For the value-initialized
MyObject obj{};
case , the compiler directly does amovq 0x0, OFFSET(%REGISTER)
for each member of the class. -
For the non-default constructor case, the compiler calls the constructor symbol
MyObject::MyObject
.