零初始化

来自cppreference.com
< cpp‎ | language

将一个对象的初始值设为零。

语法

注意零初始化在语言中没有专用语法,因此下列语法不是零初始化语法。这些是可能会进行零初始化的其他初始化的例子。

static T 对象 ; (1)
T () ;

T t = {} ;

T {} ; (C++11 起)

(2)
CharT 数组 [ n ] = " 短序列 "; (3)

解释

在下列情形进行零初始化:

1) 在所有其他初始化前,对每个具有静态或线程局部 (C++11 起)存储期的,不进行常量初始化的具名变量。
2) 作为非类类型变量,和被值初始化的无构造函数的类类型的成员的值初始化序列的一部分,包括未提供初始化器的聚合体元素的值初始化。
3) 以不够长的字符串字面量初始化任何字符类型数组时,零初始化数组的剩余部分。

零初始化的效果是:

  • 如果 T 是标量类型,那么对象的初始值是将整数字面量 0 显式转换T 的值。
  • 如果 T 是非联合体类类型,那么:
  • 初始化所有填充位为零位,
  • 零初始化所有非静态数据成员
  • 零初始化所有非虚基类子对象,并且
  • 如果对象不是基类子对象,那么也零初始化所有虚基类子对象。
  • 如果 T 是联合体类型,那么:
  • 初始化所有填充位为零位,
  • 零初始化对象的首个非静态具名数据成员。
  • 如果 T 是数组类型,那么零初始化每个元素。
  • 如果 T 是引用类型,那么不做任何事。

注解

非局部初始化中所述,在进行任何其他初始化前,零初始化所有未被常量初始化的静态和线程局部 (C++11 起)变量。如果非类类型非局部变量的定义没有初始化器,那么默认初始化不做任何事,不修改先前零初始化的结果。

零初始化的指针是其类型的空指针值,即使空指针的值并非整型的零。

示例

#include <string>
#include <iostream>
 
struct A
{
    int a, b, c;
};
 
double f[3];   // 零初始化为三个 0.0
 
int* p;        // 零初始化为空指针值(即使该值可能不是整型 0)
 
std::string s; // 零初始化为不确定值
               // 再通过 std::string 的默认构造函数默认初始化为 ""
 
int main(int argc, char* argv[])
{
    delete p; // 可以安全删除空指针
 
    static int n = argc; // 零初始化为 0,然后复制初始化为 argc
    std::cout << "n = " << n << '\n';
 
    A a = A(); // 效果等同于 A a{}; 或 A a = {};
    std::cout << "a = {" << a.a << ' ' << a.b << ' ' << a.c << "}\n";
}

输出:

n = 1
a = {0 0 0}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 出版时的行为 正确行为
CWG 277 C++98 指针可能会以值为 0 的非常量表达式进行
初始化,但后者不是空指针常量
必须以值为 0 的整数
常量表达式进行初始化
CWG 694 C++98 零初始化类类型对象时不会处理填充位 填充位会被置零
CWG 903 C++98 零初始化标量类型对象时会将初始值设为
从值为 0 的整型常量表达式转换而来的值
将该对象初始化为从整数
字面量 0 转换而来的值
CWG 2026 C++98 始终首先进行零初始化,甚至先于常量初始化 适用常量初始化时不进行零初始化
CWG 2196 C++98 零初始化类类型对象时不会考虑基类子对象 它们也会被零初始化
CWG 2253 C++98 不明确无名位域是否适用零初始化 适用(初始化所有填充位为零位)

参阅