Default-initialization
This is the initialization performed when an object is constructed with no initializer.
Contents |
Syntax
T object
;
|
(1) | ||||||||
new
T
|
(2) | ||||||||
Explanation
Default-initialization is performed in three situations:
The effects of default-initialization are:
-
if
Tis a (possibly cv-qualified) non-POD (until C++11) class type, the constructors are considered and subjected to overload resolution against the empty argument list. The constructor selected (which is one of the default constructors ) is called to provide the initial value for the new object; -
if
Tis an array type, every element of the array is default-initialized; - otherwise, no initialization is performed (see notes ).
|
Only (possibly cv-qualified) non-POD class types (or arrays thereof) with automatic storage duration were considered to be default-initialized when no initializer is used. Scalars and POD types with dynamic storage duration were considered to be not initialized (since C++11, this situation was reclassified as a form of default-initialization). |
(until C++11) |
|
(until C++11) |
|
(since C++11) |
each
potentially constructed
base class of
T
is const-default-constructible.
Indeterminate and erroneous values
|
When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value . If no initialization is performed for an object, that object retains an indeterminate value until that value is replaced. |
(until C++26) |
|
When storage for an object with automatic or dynamic storage duration is obtained, the bytes comprising the storage for the object have the following initial value:
If no initialization is performed for an object (including subobjects ), such a byte retains its initial value until that value is replaced.
|
(since C++26) |
If an evaluation produces an indeterminate value, the behavior is undefined .
|
If an evaluation produces an erroneous value, the behavior is erroneous . |
(since C++26) |
Special cases
The following types are uninitialized-friendly :
| (since C++17) |
- unsigned char
- char , if its underlying type is unsigned char
Given an indeterminate or erroneous (since C++26) value value , the uninitialized result value of value is:
- An indeterminate value, if value is also an indeterminate value.
|
(since C++26) |
If an evaluation eval produces an indeterminate or erroneous (since C++26) value value of an uninitialized-friendly type, the behavior is well-defined in the following cases:
- eval is the evaluation of one of the following expressions and operands:
-
- The second or third operand of a conditional expression .
- The right operand of a comma expression .
-
The operand of an
integral conversion
,
explicit cast
or
static_castto an uninitialized-friendly type. - A discarded-value expression .
- In this case, the result of the operation is the uninitialized result value of value .
- eval is an evaluation of the right operand of a simple assignment operator whose left operand is an lvalue of an uninitialized-friendly type.
- In this case, the value of the object referred to by the left operand is replaced by the uninitialized result value of value .
- eval is the evaluation of the initialization expression when initializing an object of an uninitialized-friendly type.
| (since C++17) |
- In this case, that object is initialized to the uninitialized result value of value .
Converting an indeterminate value of an uninitialized-friendly type produces an indeterminate value.
|
Converting an erroneous value of an uninitialized-friendly type produces an erroneous value, the result of the conversion is the value of the converted operand. |
(since C++26) |
// Case 1: Uninitialized objects with dynamic storage duration // All C++ versions: indeterminate value + undefined behavior int f(bool b) { unsigned char* c = new unsigned char; unsigned char d = *c; // OK, “d” has an indeterminate value int e = d; // undefined behavior return b ? d : 0; // undefined behavior if “b” is true } // Case 2: Uninitialized objects with automatic storage duration // until C++26: indeterminate value + undefined behavior // since C++26: erroneous value + erroneous behavior int g(bool b) { unsigned char c; // “c” has an indeterminate/erroneous value unsigned char d = c; // no undefined/erroneous behavior, // but “d” has an indeterminate/erroneous value assert(c == d); // holds, but both integral promotions have // undefined/erroneous behavior int e = d; // undefined/erroneous behavior return b ? d : 0; // undefined/erroneous behavior if “b” is true } // Same as case 2 void h() { int d1, d2; // “d1” and “d2” have indeterminate/erroneous values int e1 = d1; // undefined/erroneous behavior int e2 = d1; // undefined/erroneous behavior assert(e1 == e2); // holds assert(e1 == d1); // holds, undefined/erroneous behavior assert(e2 == d1); // holds, undefined/erroneous behavior // no undefined/erroneous behavior, // but “d2” has an indeterminate/erroneous value std::memcpy(&d2, &d1, sizeof(int)); assert(e1 == d2); // holds, undefined/erroneous behavior assert(e2 == d2); // holds, undefined/erroneous behavior }
Notes
References and const scalar objects cannot be default-initialized.
| Feature-test macro | Value | Std | Feature |
|---|---|---|---|
__cpp_constexpr
|
201907L
|
(C++20) | Trivial default-initialization and asm-declaration in constexpr functions |
Example
#include <string> struct T1 { int mem; }; struct T2 { int mem; T2() {} // “mem” is not in the initializer list }; int n; // static non-class, a two-phase initialization is done: // 1) zero-initialization initializes n to zero // 2) default-initialization does nothing, leaving n being zero int main() { [[maybe_unused]] int n; // non-class, the value is indeterminate std::string s; // class, calls default constructor, the value is "" std::string a[2]; // array, default-initializes the elements, the value is {"", ""} // int& r; // Error: a reference // const int n; // Error: a const non-class // const T1 t1; // Error: const class with implicit default constructor [[maybe_unused]] T1 t1; // class, calls implicit default constructor const T2 t2; // const class, calls the user-provided default constructor // t2.mem is default-initialized }
Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
| DR | Applied to | Behavior as published | Correct behavior |
|---|---|---|---|
| CWG 178 | C++98 |
there was no value-initialization;
empty initializer invoked default-initialization (though new T ( ) also performs zero-initialization) |
empty initializer invokes
value-initialization |
| CWG 253 | C++98 |
default-initialization of a const object could not
call an implicitly declared default constructor |
allowed if all subobjects are initialized |
| CWG 616 | C++98 |
lvalue to rvalue conversion of any
uninitialized object was always UB |
indeterminate unsigned char is allowed |
| CWG 1787 | C++98 |
read from an indeterminate
unsigned
char
cached in a register was UB |
made well-defined |