为什么我的struct的成员没有使用`{}`正确初始化?

Lig*_*ica 14 c++ initialization c++-faq

我有以下代码:

#include <iostream>

struct T
{
   int a, b, c;
};

int main()
{
   T t = {0};
   std::cout << t.a << ',' << t.b << ',' << t.c << '\n';
}
Run Code Online (Sandbox Code Playgroud)

输出:

0,0,0
Run Code Online (Sandbox Code Playgroud)

经过多年的代码在一个关键的生产环境中愉快地运行,提供一个重要的功能,项目的要求发生了变化,我需要输出1,1,1.

于是,我换{0}{1}:

#include <iostream>

struct T
{
   int a, b, c;
};

int main()
{
   T t = {1};
   std::cout << t.a << ',' << t.b << ',' << t.c << '\n';
}
Run Code Online (Sandbox Code Playgroud)

输出:

1,0,0
Run Code Online (Sandbox Code Playgroud)

1,1,1反而期待了.

为什么我struct的成员并非都被正确初始化?

Lig*_*ica 32

= {0}时,只显式初始化第一个成员 ; 其余都是零初始化隐含根据标准,因此出现在你明确初始化所有成员的第一眼0,你写的,但你没有.

您编写的地方0仅影响第一个成员.因此,有一天,当你改变它以1认为它会改变所有成员时,你会有一个错误,就像这里一样.这是误导/危险/愚蠢/脆弱的代码.

因此,如果没有附带的解释性评论,= {0}我的团队将不会通过代码审查.你本来应该写的:

T t = {};
Run Code Online (Sandbox Code Playgroud)

现在,要根据新要求解决您的问题,您应该写:

T t = {1,1,1};
Run Code Online (Sandbox Code Playgroud)

或者,如果你不介意你struct可能失去POD,请给T一个构造函数.


正式的措辞

[C++11: 8.5.1/2]:当初始化程序列表初始化聚合时,如8.5.4中所述,初始化程序列表的元素将作为聚合成员的初始化程序,增加下标或成员顺序.每个成员都是从相应的initializer子句复制初始化的.如果initializer子句是表达式并且转换表达式需要缩小转换(8.5.4),则程序格式错误.[..]

[C++11: 8.5.1/6]:一个初始化列表如果数量是形成不良的初始化子句超过构件或元件来初始化的数量.

[C++11: 8.5.1/7]: 如果列表中的initializer-clause少于聚合中的成员,则未显式初始化的每个成员都应从空的初始化列表(8.5.4)初始化.

  • 在C(而不是C++)中,`= {0}`符号是将所有字段初始化为零的古老传统.某些版本的GCC在给出适当的选项时会警告"未完全初始化的结构"(例如4.1.x到4.6.x); 更新的版本(例如GCC 4.7.1)将`= {0}`识别为特殊情况,并且在使用该表示法时不生成警告.使用缩写表示法的一个原因是避免在结构改变时必须更改初始化程序.(我不打算就这如何适用于C++进行教诲.) (11认同)