默认初始化
这是在用无初始化器构造对象时执行的初始化。
内容 |
[编辑] 语法
T 对象 ; |
(1) | ||||||||
new T |
(2) | ||||||||
[编辑] 解释
默认初始化在三种情况下执行
默认初始化的效果是
- 如果
T
是一个(可能限定为 cv 的)非 POD(直到 C++11) 类类型,则会考虑构造函数,并针对空参数列表进行重载解析。选择的构造函数(是默认构造函数之一)被调用,以提供新对象的初始值; - 如果
T
是一个数组类型,则数组的每个元素都会被默认初始化; - 否则,不会执行初始化(参见注释)。
[编辑] const 对象的默认初始化
如果程序要求对一个const 限定类型 T
的对象进行默认初始化,则 T
必须是一个const-default-constructible 类类型或其数组。
如果对 T
进行默认初始化将调用 T
的用户提供的构造函数(而不是从基类继承的)(从 C++11 开始),或者如果
只有具有自动存储持续时间的(可能限定为 cv 的)非 POD 类类型(或其数组)在没有初始化器的情况下被认为是默认初始化的。具有动态存储持续时间的标量和 POD 类型被认为是未初始化的(从 C++11 开始,这种情况被重新归类为默认初始化的一种形式)。 |
(直到 C++11) |
|
(直到 C++11) |
(从 C++11 开始) |
T
的每个可能构造的基类都是 const-default-constructible。
[编辑] 不确定的值和错误的值
当为具有自动或动态存储期的对象获取存储空间时,该对象具有不确定的值。 如果未对对象进行初始化,则该对象会保留不确定的值,直到该值被替换。 |
(直到 C++26) |
当为具有自动或动态存储期的对象获取存储空间时,构成该对象存储空间的字节具有以下初始值
如果未对对象(包括子对象)进行初始化,则此类字节会保留其初始值,直到该值被替换。
|
(自 C++26 起) |
如果求值产生不确定的值,则行为是未定义的。
如果求值产生错误的值,则行为是错误的。 |
(自 C++26 起) |
[编辑] 特殊情况
以下类型是未初始化友好的
(自 C++17 起) |
- unsigned char
- char,如果其底层类型是unsigned char
给定一个不确定的或错误的(自 C++26 起)值value,value的未初始化结果值是
- 不确定的值,如果value也是不确定的值。
|
(自 C++26 起) |
如果求值eval产生一个不确定的或错误的(自 C++26 起)值value,它属于未初始化友好类型,则在以下情况下行为是明确定义的
- eval是以下表达式和操作数之一的求值
- eval是对简单赋值运算符的右操作数的求值,其左操作数是未初始化友好类型的左值。
- 在这种情况下,左操作数引用的对象的值将被value的未初始化结果值替换。
- eval是初始化未初始化友好类型对象时初始化表达式的求值。
(自 C++17 起) |
- 在这种情况下,该对象将被初始化为value的未初始化结果值。
转换未初始化友好类型的非确定值会产生非确定值。
转换未初始化友好类型的错误值会产生错误的值,转换的结果是转换操作数的值。 |
(自 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 }
[编辑] 注释
引用和 const 标量对象不能进行默认初始化。
功能测试宏 | 值 | Std | 功能 |
---|---|---|---|
__cpp_constexpr |
201907L | (C++20) | 在constexpr 函数中进行平凡的默认初始化和asm 声明 |
[编辑] 示例
#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 }
[编辑] 缺陷报告
以下更改行为的缺陷报告被追溯应用于之前发布的 C++ 标准。
DR | 应用于 | 发布的行为 | 正确行为 |
---|---|---|---|
CWG 178 | C++98 | 没有值初始化; 空初始化器调用默认初始化 (尽管new T() 也执行零初始化) |
空初始化器调用 值初始化 |
CWG 253 | C++98 | const 对象的默认初始化不能 调用隐式声明的默认构造函数 |
如果所有子对象都被初始化,则允许 |
CWG 616 | C++98 | 任何 未初始化对象的左值到右值转换始终是 UB |
允许不确定的unsigned char |
CWG 1787 | C++98 | 从不确定的unsigned char 缓存到寄存器中是 UB |
变为明确定义 |