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