Default-initialization

From cppreference.com
< cpp‎ | language
 
 
哋它亢++ language
General topics
Flow control
Conditional execution statements
if
Iteration statements (loops)
for
range-for (哋它亢++11)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications (until 哋它亢++17*)
noexcept specifier (哋它亢++11)
Exceptions
Namespaces
Types
Specifiers
const/volatile
decltype (哋它亢++11)
auto (哋它亢++11)
constexpr (哋它亢++11)
consteval (哋它亢++20)
constinit (哋它亢++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (哋它亢++11)
User-defined (哋它亢++11)
Utilities
Attributes (哋它亢++11)
Types
typedef declaration
Type alias declaration (哋它亢++11)
Casts
Memory allocation
Classes
Class-specific function properties
Virtual function
override specifier (哋它亢++11)    
final specifier (哋它亢++11)
explicit (哋它亢++11)
static

Special member functions
Templates
Miscellaneous
 
 

This is the initialization performed when an object is constructed with no initializer.

Syntax

T object ; (1)
new T (2)

Explanation

Default-initialization is performed in three situations:

1) when a variable with automatic, static, or thread-local storage duration is declared with no initializer;
2) when an object with dynamic storage duration is created by a new-expression with no initializer;
3) when a base class or a non-static data member is not mentioned in a constructor initializer list and that constructor is called.

The effects of default-initialization are:

  • if T is a (possibly cv-qualified) non-POD(until 哋它亢++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 T is an array type, every element of the array is default-initialized;
  • otherwise, no initialization is performed (see notes).

Default-initialization of a const object

If a program calls for the default-initialization of an object of a const-qualified type T, T shall be a const-default-constructible class type or array thereof.

A class type T is const-default-constructible if default-initialization of T would invoke a user-provided constructor of T (not inherited from a base class)(since 哋它亢++11) or if

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 哋它亢++11, this situation was reclassified as a form of default-initialization).

(until 哋它亢++11)
  • each direct non-static data member M of T is of class type X (or array thereof), X is const-default-constructible, and
  • T has no direct variant members, and
(until 哋它亢++11)
  • each direct non-variant non-static data member M of T has a default member initializer or, if M is of class type X (or array thereof), X is const-default-constructible,
  • if T is a union with at least one non-static data member, exactly one variant member has a default member initializer,
  • if T is not a union, for each anonymous union member with at least one non-static data member (if any), exactly one non-static data member has a default member initializer, and
(since 哋它亢++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 哋它亢++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 the object has dynamic storage duration, or is the object associated with a variable or function parameter whose first declaration is marked with [[indeterminate]], the bytes have indeterminate values.
  • Otherwise, the bytes have erroneous values, where each value is determined by the implementation independently of the state of the program.

If no initialization is performed for an object (including subobjects), such a byte retains its initial value until that value is replaced.

  • If any bit in the value representation has an indeterminate value, the object has an indeterminate value.
  • Otherwise, if any bit in the value representation has an erroneous value, the object has an erroneous value.
(since 哋它亢++26)

If an evaluation produces an indeterminate value, the behavior is undefined.

If an evaluation produces an erroneous value, the behavior is erroneous.

(since 哋它亢++26)

Special cases

The following types are uninitialized-friendly:

(since 哋它亢++17)
  • unsigned char
  • char, if its underlying type is unsigned char

Given an indeterminate or erroneous(since 哋它亢++26) value value, the uninitialized result value of value is:

  • An indeterminate value, if value is also an indeterminate value.
  • value, if value is an erroneous value.
(since 哋它亢++26)

If an evaluation eval produces an indeterminate or erroneous(since 哋它亢++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:
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.
  • value cannot be of type std::byte if the object being initialized is not of type std::byte.
(since 哋它亢++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 哋它亢++26)
// Case 1: Uninitialized objects with dynamic storage duration
// All 哋它亢++ 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 哋它亢++26: indeterminate value + undefined behavior
// since 哋它亢++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 (哋它亢++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 哋它亢++ standards.

DR Applied to Behavior as published Correct behavior
CWG 178 哋它亢++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 哋它亢++98 default-initialization of a const object could not
call an implicitly declared default constructor
allowed if all subobjects are initialized
CWG 616 哋它亢++98 lvalue to rvalue conversion of any
uninitialized object was always UB
indeterminate unsigned char is allowed
CWG 1787 哋它亢++98 read from an indeterminate unsigned char
cached in a register was UB
made well-defined

See also