Namespaces
Variants

Default-initialization

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

这是在对象以无初始化器方式构造时执行的初始化过程。

目录

语法

T 对象  ; (1)
new T (2)

说明

默认初始化在三种情况下执行:

1) 当具有自动、静态或线程局部 存储期 的变量在声明时未提供初始化器;
2) 当具有动态存储期的对象通过不带初始化器的 new-expression 创建时;
3) 当基类或非静态数据成员未在 构造函数初始化列表 中被提及且该构造函数被调用时。

默认初始化的效果是:

  • T 是(可能带有 cv 限定符的) 非 POD (C++11 前) 类类型,将考虑构造函数并通过 重载决议 匹配空参数列表。所选构造函数(即 默认构造函数 之一)将被调用来为新对象提供初始值;
  • T 是数组类型,数组的每个元素都将进行默认初始化;
  • 否则,不执行任何初始化(参见 注释 )。

const 对象的默认初始化

如果程序要求对 const 限定类型 T 的对象进行默认初始化,则 T 应为 const 默认可构造 的类类型或其数组。

如果 T 的默认初始化会调用 T 的用户提供构造函数 (非从基类继承) (C++11 起) ,或者满足以下条件,则类类型 T 是 const 默认可构造的:

当未使用初始化器时,只有(可能带有 cv 限定符的)非 POD 类类型(或其数组)具有自动存储期才会被视为默认初始化。标量和具有动态存储期的 POD 类型被视为未初始化(自 C++11 起,这种情况被重新分类为默认初始化的一种形式)。

(C++11 前)
  • T 的每个直接非静态数据成员 M 是类类型 X (或其数组),且 X 是 const 默认可构造的,并且
  • T 没有直接 变体成员 ,并且
(C++11 前)
  • T 的每个直接非变体非静态数据成员 M 具有 默认成员初始化器 ,或者如果 M 是类类型 X (或其数组),则 X 是 const 默认可构造的,
  • 如果 T 是至少有一个非静态数据成员的联合体,则恰好有一个 变体成员 具有默认成员初始化器,
  • 如果 T 不是联合体,对于每个具有至少一个非静态数据成员的匿名联合体成员(如果有),恰好有一个非静态数据成员具有默认成员初始化器,并且
(C++11 起)

T 的每个 潜在构造 基类是 const 默认可构造的。

不确定值和错误值

当获取具有自动或动态存储期的对象的存储时,该对象具有 不确定值

如果对象未执行任何初始化,则该对象保留不确定值,直到该值被替换。

(C++26 前)

当获取具有自动或动态存储期的对象的存储时,组成该对象存储的字节具有以下初始值:

  • 如果对象具有动态存储期,或者是其首次声明标记为 [[ indeterminate ]] 的变量或 函数参数 关联的对象,则字节具有 不确定值
  • 否则,字节具有 错误值 ,其中每个值由实现独立于程序状态确定。

如果对象(包括 子对象 )未执行任何初始化,则此类字节保留其初始值,直到该值被替换。

  • 如果 值表示 中的任何位具有不确定值,则对象具有 不确定值
  • 否则,如果值表示中的任何位具有错误值,则对象具有 错误值
(C++26 起)

如果求值产生不确定值,则行为是 未定义 的。

如果求值产生错误值,则行为是 错误 的。

(C++26 起)

特殊情况

以下类型是 未初始化友好 的:

(C++17 起)
  • unsigned char
  • char ,如果其底层类型是 unsigned char

给定不确定 或错误 (C++26 起) value value 未初始化结果值 是:

  • 不确定值,如果 value 也是不确定值。
  • value ,如果 value 是错误值。
(C++26 起)

如果求值 eval 产生未初始化友好类型的不确定 或错误 (C++26 起) value ,则在以下情况下行为是良定义的:

  • eval 是以下表达式及其操作数的求值:
在这种情况下,操作的结果是 value 的未初始化结果值。
在这种情况下,左操作数引用的对象的值被替换为 value 的未初始化结果值。
  • eval 是初始化未初始化友好类型对象时的初始化表达式的求值。
(C++17 起)
在这种情况下,该对象被初始化为 value 的未初始化结果值。

转换未初始化友好类型的不确定值会产生不确定值。

转换未初始化友好类型的错误值会产生错误值,转换结果是转换后操作数的值。

(C++26 起)
// 情况 1:具有动态存储期的未初始化对象
// 所有 C++ 版本:不确定值 + 未定义行为
int f(bool b)
{
    unsigned char* c = new unsigned char;
    unsigned char d = *c; // OK,“d”具有不确定值
    int e = d;            // 未定义行为
    return b ? d : 0;     // 如果“b”为 true 则未定义行为
}
// 情况 2:具有自动存储期的未初始化对象
// C++26 前:不确定值 + 未定义行为
// C++26 起:错误值 + 错误行为
int g(bool b)
{
    unsigned char c;     // “c”具有不确定/错误值
    unsigned char d = c; // 无未定义/错误行为,
                         // 但“d”具有不确定/错误值
    assert(c == d);      // 成立,但两个整型提升具有
                         // 未定义/错误行为
    int e = d;           // 未定义/错误行为
    return b ? d : 0;    // 如果“b”为 true 则未定义/错误行为
}
// 同情况 2
void h<span class="