use*_*522 9 c++ constructor value-initialization c++11 visual-studio-2013
请考虑以下代码
struct B
{
B() : member{}{};
int member[10];
};
int main()
{
B b;
}
Run Code Online (Sandbox Code Playgroud)
VS2013编译器发出以下警告:
警告C4351:新行为:数组'B :: member'的元素将默认初始化1> test.vcxproj - > C:\ Users\asaxena2\documents\visual studio 2013\Projects\test\Debug\test.exe
使用C++ 11,并应用"默认初始化"的概念,意味着B.member的元素将不会被初始化.
但我相信member{}应该执行值初始化而不是默认初始化.VS2013编译器坏了吗?
$ 7.0/6
默认初始化类型对象
T意味着: - 如果T是(可能是cv限定的)类类型(第9节),T则调用默认构造函数(如果T没有可访问的默认构造函数,则初始化是错误的);
- 如果T是数组类型,则每个元素都是默认初始化的;
- 否则,不执行初始化.
如果程序要求对const-qualified类型的对象进行默认初始化T,则T应该是具有用户提供的默认构造函数的类类型.
$ 8.5.1
对象或类型引用的列表初始化
T定义如下:
- 如果初始化列表没有元素并且T是具有默认构造函数的类类型,则对象是值初始化的.
- 否则,如果T是聚合,则执行聚合初始化(8.5.1).如果列表中的initializer-clause少于聚合中的成员,则未显式初始化的每个成员都应从空的初始化列表(8.5.4)初始化.[ 例如:
Run Code Online (Sandbox Code Playgroud)struct S { int a; const char* b; int c; }; S ss = { 1, "asdf" };初始化
ss.awith1,ss.bwith"asdf"和ss.cwith表达式的表达式int(),即0.- 末端的例子 ]
它似乎是一个措辞不正确的警告信息(我很惊讶它首先打印一个警告),但行为是正确的.B::member正在进行值初始化,这对于一组int转换为零初始化.这可以通过以下方式证明:
#include <iostream>
struct B
{
B() : member{}{};
int member[10];
};
struct C
{
C() {};
int member[10];
};
int main()
{
B b;
for(auto const& a : b.member) std::cout << a << ' ';
std::cout << std::endl;
C c;
for(auto const& a : c.member) std::cout << a << ' ';
std::cout << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
如果在Debug模式下编译并运行,则会产生输出:
0 0 0 0 0 0 0 0 0 0
-858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460
Run Code Online (Sandbox Code Playgroud)
第二行中的数字是0xCCCCCCCCVC++编译器在调试模式下填充内存的调试模式.因此B::member,零初始化,而不执行初始化C::member.
免责声明:我知道从未初始化的变量读取是未定义的行为,但这是我能想到的最好的证明.