I am very confused about value- & default- & zero-initialization. and especially when they kick in for the different standards C++03 and C++11 (and C++14).
I am quoting and trying to extend a really good answer Value-/Default-/Zero- Init C++98 and C++03 here to make it more general as it would help a lot of users if somebody could help fill out the needed gaps to have a good overview about what happens when?
The full insight by examples in a nutshell:
Sometimes the memory returned by the new operator will be initialized, and sometimes it won't depending on whether the type you're newing up is a POD (plain old data), or if it's a class that contains POD members and is using a compiler-generated default constructor.
Assume:
struct A { int m; }; struct B { ~B(); int m; }; struct C { C() : m(){}; ~C(); int m; }; struct D { D(){}; int m; }; struct E { E() = default; int m;}; /** only possible in c++11/14 */ struct F {F(); int m;}; F::F() = default; /** only possible in c++11/14 */
In a C++98 compiler, the following should occur:
new A
- indeterminate value (A
is POD)new A()
- zero-initializenew B
- default construct (B::m
is uninitialized, B
is non-POD)new B()
- default construct (B::m
is uninitialized)new C
- default construct (C::m
is zero-initialized, C
is non-POD)new C()
- default construct (C::m
is zero-initialized)new D
- default construct (D::m
is uninitialized, D
is non-POD)new D()
- default construct? (D::m
is uninitialized)In a C++03 conformant compiler, things should work like so:
new A
- indeterminate value (A
is POD)new A()
- value-initialize A
, which is zero-initialization since it's a POD.new B
- default-initializes (leaves B::m
uninitialized, B
is non-POD)new B()
- value-initializes B
which zero-initializes all fields since its default ctor is compiler generated as opposed to user-defined.new C
- default-initializes C
, which calls the default ctor. (C::m
is zero-initialized, C
is non-POD)new C()
- value-initializes C
, which calls the default ctor. (C::m
is zero-initialized)new D
- default construct (D::m
is uninitialized, D
is non-POD)new D()
- value-initializes D?, which calls the default ctor (D::m
is uninitialized)Italic values and ? are uncertainties, please help to correct this :-)
In a C++11 conformant compiler, things should work like so:
??? (please help if I start here it will anyway go wrong)
In a C++14 conformant compiler, things should work like so: ??? (please help if I start here it will anyway go wrong) (Draft based on answer)
new A
- default-initializes A
, compiler gen. ctor, (leavs A::m
uninitialized) (A
is POD)
new A()
- value-initializes A
, which is zero-initialization since 2. point in [dcl.init]/8
new B
- default-initializes B
, compiler gen. ctor, (leavs B::m
uninitialized) (B
is non-POD)
new B()
- value-initializes B
which zero-initializes all fields since its default ctor is compiler generated as opposed to user-defined.
new C
- default-initializes C
, which calls the default ctor. (C::m
is zero-initialized, C
is non-POD)
new C()
- value-initializes C
, which calls the default ctor. (C::m
is zero-initialized)
new D
- default-initializes D
(D::m
is uninitialized, D
is non-POD)
new D()
- value-initializes D
, which calls the default ctor (D::m
is uninitialized)
new E
- default-initializes E
, which calls the comp. gen. ctor. (E::m
is uninitialized, E is non-POD)
new E()
- value-initializes E
, which zero-initializes E
since 2 point in [dcl.init]/8 )
new F
- default-initializes F
, which calls the comp. gen. ctor. (F::m
is uninitialized, F
is non-POD)
new F()
- value-initializes F
, which default-initializes F
since 1. point in [dcl.init]/8 (F
ctor function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration. Link)
Implicitly defined (by the compiler) default constructor of a class does not initialize members of built-in types.
Problem of initialization in C++ Therefore, when objects are created, the members of the object cannot be initialized directly and this problem of not being able to initialize data members is known as the problem of initialization.
Instance variables of numerical type (int, double, etc.) are automatically initialized to zero if you provide no other values; boolean variables are initialized to false; and char variables, to the Unicode character with code number zero.
Default member initializer (C++11) [edit] This is the initialization performed when an object is constructed with no initializer.
C++14 specifies initialization of objects created with new
in [expr.new]/17 ([expr.new]/15 in C++11, and the note wasn't a note but normative text back then):
A new-expression that creates an object of type
T
initializes that object as follows:
- If the new-initializer is omitted, the object is default-initialized (8.5). [ Note: If no initialization is performed, the object has an indeterminate value. — end note ]
- Otherwise, the new-initializer is interpreted according to the initialization rules of 8.5 for direct-initialization.
Default-initialization is defined in [dcl.init]/7 (/6 in C++11, and the wording itself has the same effect):
To default-initialize an object of type
T
means:
- if
T
is a (possibly cv-qualified) class type (Clause 9), the default constructor (12.1) forT
is called (and the initialization is ill-formed ifT
has no default constructor or overload resolution (13.3) results in an ambiguity or in a function that is deleted or inaccessible from the context of the initialization);- if
T
is an array type, each element is default-initialized;- otherwise, no initialization is performed.
Thus
new A
solely causes A
s default constructor to be called, which does not initialize m
. Indeterminate value. Should be the same for new B
.new A()
is interpreted according to [dcl.init]/11 (/10 in C++11):
An object whose initializer is an empty set of parentheses, i.e.,
()
, shall be value-initialized.
And now consider [dcl.init]/8 (/7 in C++11†):
To value-initialize an object of type
T
means:
- if
T
is a (possibly cv-qualified) class type (Clause 9) with either no default constructor (12.1) or a default constructor that is user-provided or deleted, then the object is default-initialized;- if
T
is a (possibly cv-qualified) class type without a user-provided or deleted default constructor, then the object is zero-initialized and the semantic constraints for default-initialization are checked, and if T has a non-trivial default constructor, the object is default-initialized;- if
T
is an array type, then each element is value-initialized;- otherwise, the object is zero-initialized.
Hence new A()
will zero-initialize m
. And this should be equivalent for A
and B
.
new C
and new C()
will default-initialize the object again, since the first bullet point from the last quote applies (C has a user-provided default constructor!). But, clearly, now m
is initialized in the constructor in both cases.
† Well, this paragraph has slightly different wording in C++11, which does not alter the result:
To value-initialize an object of type
T
means:
- if
T
is a (possibly cv-qualified) class type (Clause 9) with a user-provided constructor (12.1), then the default constructor forT
is called (and the initialization is ill-formed if T has no accessible default constructor);- if
T
is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object is zero-initialized and, ifT
’s implicitly-declared default constructor is non-trivial, that constructor is called.- if
T
is an array type, then each element is value-initialized;- otherwise, the object is zero-initialized.
The following answer extends the answer https://stackoverflow.com/a/620402/977038 which would serve as a reference for C++ 98 and C++ 03
Quoting the answer
C++11 (In reference to n3242)
8.5 Initializers [dcl.init] specifies that a variable POD or non POD can be initialized either as brace-or-equal-initializer which can either be braced-init-list or initializer-clause aggregately referred to as brace-or-equal-initializer or using ( expression-list ). Previous to C++11, only (expression-list) or initializer-clause was supported though initializer-clause was more restricted then what we have in C++11. In C++11, initializer-clause now supports braced-init-list apart from assignment-expression as was in C++03. The following grammar summarizes the new supported clause, where the part is bold is newly added in the C++11 standard.
initializer:
    brace-or-equal-initializer
    ( expression-list )
brace-or-equal-initializer:
    = initializer-clause
    braced-init-list
initializer-clause:
    assignment-expression
    braced-init-list
initializer-list:
    initializer-clause ...opt
    initializer-list , initializer-clause ...opt**
braced-init-list:
    { initializer-list ,opt }
    { }
Like C++03, C++11 still supports three form of initialize
Note
The part highlighted in bold has been added in C++11 and the one that is striked out has been removed from C++11.
Performed in the following cases
To zero-initialize an object or reference of type T means:
- if T is a scalar type (3.9), the object is set to the value 0 (zero), taken as an integral constant expression, converted to T;
- if T is a (possibly cv-qualified) non-union class type, each non-static data member and each base-class subobject is zero-initialized and padding is initialized to zero bits;
- if T is a (possibly cv-qualified) union type, the object’s first non-static named data member is zero initialized and padding is initialized to zero bits;
- if T is an array type, each element is zero-initialized;
- if T is a reference type, no initialization is performed.
Performed in the following cases
To default-initialize an object of type T means:
- if T is a (possibly cv-qualified)
non-PODclass type (Clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);- if T is an array type, each element is default-initialized;
- otherwise, no initialization is performed.
Note Until C++11, only non-POD class types with automatic storage duration were considered to be default-initialized when no initializer is used.
To value-initialize an object of type T means:
- if T is a (possibly cv-qualified) class type (Clause 9) with a user-provided 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 (possibly cv-qualified) non-union class type without a user-provided constructor,
then every non-static data member and base-class component of T is value-initialized;then the object is zero-initialized and, if T’s implicitly-declared default constructor is non-trivial, that constructor is called.- if T is an array type, then each element is value-initialized;
- otherwise, the object is zero-initialized.
So to summarize
Note The relevant quotation from the standard is highlighted in bold
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With