C++ 11 VS2013类POD成员初始化

Apr*_*ori 5 c++ visual-studio c++11

我到处寻找对此的解释,但我很快就会出现.我从VS2013 v120平台工具集中看到了这种行为,但是当我将工具集设置为v90(VS2008工具集)时,一切都未初始化.我相信这是由于C++ 11的一些变化,但它也可能是v120平台工具集的异常.

任何人都可以在C++/C++ 11级别上解释这里发生了什么吗?那就是为什么b归零?为什么j不归零呢?(也就是为什么结构体的行为与类不同)

另外,我知道我输出数据的方式是未定义的行为,请忽略它.这里发布的方式比调试器窗口更容易.这是在32位运行,因此指针的大小与unsigned int相同.

请考虑以下代码:

#include <iostream>

class Foo {
public:
  int a,
      *p;
};

class Bar {
public:
  Bar(){}
  int a,
      *p;
};

struct Jar {
  Jar(){}
  int a,
      *p;
};

int main() {
  Foo f;
  Bar b;
  Jar j;
  std::cout << std::hex; // please excuse this undefined-behavior producing test code, it's more simple to show this than a debugger window on SO (this is on 32-bit)
  std::cout << "f: " << ((unsigned*)&f)[0] << ' ' << ((unsigned*)&f)[1] << std::endl;
  std::cout << "b: " << ((unsigned*)&b)[0] << ' ' << ((unsigned*)&b)[1] << std::endl;
  std::cout << "j: " << ((unsigned*)&j)[0] << ' ' << ((unsigned*)&j)[1] << std::endl;
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是输出:

f: cccccccc cccccccc  
b: 0 0  
j: cccccccc cccccccc
Run Code Online (Sandbox Code Playgroud)

编辑:
这是我看到的与Bar b;__autoclassinit2 关联的反汇编内存.它不是构造函数的一部分,而是在构造函数调用之前归零.

  Bar b;
00886598  push        8  
0088659A  lea         ecx,[b]  
0088659D  call        Bar::__autoclassinit2 (0881181h)  
008865A2  lea         ecx,[b]  
008865A5  call        Bar::Bar (0881109h)  
Run Code Online (Sandbox Code Playgroud)

Pra*_*ian 6

所有类型都包含内置类型的数据成员,因此除非您执行以下操作之一,否则它们都不会进行零初始化(以示例为例Foo):

初始化默认构造函数中的成员:

class Foo {
public:
  Foo() : a(), p() {}
  int a,
      *p;
};
Run Code Online (Sandbox Code Playgroud)

或非静态数据成员初始值设定项(括号或等于初始化程序)

class Foo {
public:
  int a = 0,
      *p = nullptr;
};
Run Code Online (Sandbox Code Playgroud)

Foo保持不变,并初始化实例的值

Foo f{};
Run Code Online (Sandbox Code Playgroud)

使用原始示例,我无法使用VS2013,32位调试版本重现您观察到的结果.我得到的输出是

f: cccccccc cccccccc
b: cccccccc cccccccc
j: cccccccc cccccccc
Run Code Online (Sandbox Code Playgroud)

编辑:我能够重现b零初始化的行为.如果启用/sdl(安全开发生命周期检查)编译器开关(在配置属性 - > C/C++ - >常规下),则会发生这种情况.

从交换机的MSDN文档:

/sdl被启用时,编译器生成代码,以在运行时执行这些检查:
- ...
-执行类成员初始化.在对象实例化时(在构造函数运行之前)自动将所有类成员初始化为零.这有助于防止使用与构造函数未显式初始化的类成员关联的未初始化数据.

这篇博文甚至提到了这个__autoclassinit功能,虽然他列出的启发式方法并不完全符合我们观察的内容,因为这个功能的行为在VS2012和VS2013 之间发生了变化.

同样值得一提的是,编译器似乎不仅区分聚合(Foo)和非聚合(另外两个),这是有道理的,但是,出于一些真正奇怪的原因,它只会在你使用时执行这种零初始化在类的关键字 class,而不是struct在类定义.