9

考虑下面VS2013缺省初始化VS值初始化

struct B 
{ 
    B() : member{}{}; 
    int member[10]; 
}; 

int main() 
{ 
    B b; 
} 

VS2013编译器的代码给出以下警告:

警告C4351:新的行为:数组 'B ::构件' 的元件将 缺省初始化1> test.vcxproj - > C:\用户\ asaxena2 \文件\视觉工作室 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)。

如果列表中的初始化子句少于聚合中的成员,则未初始化的每个成员都应从空初始化列表(8.5.4)初始化。 [实施例

​​

初始化ss.a1ss.b"asdf",和ss.c与表单int()的表达式的值,即,0末端例如]

+0

这是一个很好的问题,但“Visual Studio编译器行为”是一个可怕的标题。考虑将其改为更有意义的东西。也就是说,你是否验证过编译器的行为?这可能只是一个误导性的警告。 – hvd

+0

@ hvd:改变了它。谢谢 – user3701522

回答

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; 
} 

如果编译和运行调试模式这导致输出:这可以通过以下证明

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

我也检查了反汇编,并且看到了memset对成员变量大小的较大值的调用。所以,对memset有一个明确的调用,这意味着它按照标准的要求进行初始化为零。对于较小的n值,它以不同的方式优化和设置0(逐个元素) – user3701522

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' 
} 
0

MSDN page说:

C4351意味着你应该检查你的代码...如果你想在新 行为,这是可能的,因为数组是明确添加到 构造函数的成员初始化列表中,使用warning pragma 来禁用该警告。对于大多数 用户来说,新行为应该没问题。

因此,您必须为整行文件添加一行#pragma warning (suppress:4351)#pragma warning (disable:4351)