考虑以下代码
struct B
{
B() : member{}{};
int member[10];
};
int main()
{
B b;
}
VS2013编译器发出以下警告:
警告C4351:新行为:数组'B :: member'的元素将是 默认初始化1> test.vcxproj - > C:\ Users \ asaxena2 \ documents \ visual studio 2013 \项目\测试\调试\ TEST.EXE
记录在案here
使用C ++ 11,并应用“默认初始化”的概念,意味着B.member的元素不会被初始化。
但我相信member{}
应该执行值初始化而不是默认初始化。 VS2013编译器坏了吗?
$ 7.0 / 6
默认初始化
T
类型的对象意味着: - 如果T
是(可能是cv限定的)类类型(第9条),则调用T
的默认构造函数(如果T
无法访问,则初始化结构不正确默认构造函数);
- 如果T
是数组类型,则每个元素都是默认初始化的;
- 否则,不执行初始化 如果程序要求对const
- 限定类型T
的对象进行默认初始化,则T
应为具有用户提供的默认构造函数的类类型。
$ 8.5.1
类型
T
的对象或引用的列表初始化定义如下:
- 如果初始化列表没有元素且T
是具有默认构造函数的类类型,则对象将进行值初始化。
- 否则,如果T
是聚合,则执行聚合初始化(8.5.1)。如果列表中的initializer-clause少于聚合中的成员,则未显式初始化的每个成员都应从空的初始化列表(8.5.4)初始化。 [示例:
struct S { int a; const char* b; int c; }; S ss = { 1, "asdf" };
使用
ss.a
初始化1
,使用ss.b
初始化"asdf"
,使用ss.c
形式的表达式值初始化int()
,是,0
。 -end example ]
答案 0 :(得分:7)
这似乎是一个措辞不正确的警告信息(我很惊讶它首先打印一个警告),但行为是正确的。 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;
}
如果您在 Debug 模式下编译并运行,则会产生输出:
0 0 0 0 0 0 0 0 0 0
-858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460
第二行中的数字是0xCCCCCCCC
,VC ++编译器在调试模式下填充内存的调试模式。因此,B::member
被初始化为零,而没有为C::member
执行初始化。
免责声明:我知道从未初始化的变量中读取是未定义的行为,但这是我能想到的最好的证明。
答案 1 :(得分:2)
编译器警告不正确;它实际上正在执行标准所要求的值初始化。
示例:
#include <iostream>
struct B {
B() : member{}{};
int member[10];
};
int main() {
int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
B &b = *new (a) B;
std::cout << b.member[9]; // prints '0'
}
答案 2 :(得分:0)