简体   繁体   English

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

[英]C++11 VS2013 class POD member initialization

I've looked everywhere for an explanation for this but am coming up short. 我到处寻找对此的解释,但我很快就会出现。 I'm seeing this behavior from the VS2013 v120 platform toolset, but when I set the toolset to v90 (the VS2008 toolset) everything is uninitialized. 我从VS2013 v120平台工具集中看到了这种行为,但是当我将工具集设置为v90(VS2008工具集)时,一切都未初始化。 I believe this is due to some change in C++11, but it could also be an anomaly of the v120 platform toolset. 我相信这是由于C ++ 11的一些变化,但它也可能是v120平台工具集的异常。

Can anyone explain what's going on here on the C++/C++11 level? 任何人都可以在C ++ / C ++ 11级别上解释这里发生了什么吗? That is, why is b zeroed out? 也就是说,为什么b归零? And why is j not also zeroed out? 为什么j也没有归零? (ie why is the behavior different for structs than for classes) (也就是为什么结构体的行为与类不同)

Also, I know the way I'm outputting data is undefined behavior, please ignore that. 另外,我知道我输出数据的方式是未定义的行为,请忽略它。 It's easier to post that way here than a debugger window. 这里发布的方式比调试器窗口更容易。 This is running on 32-bit, so pointers are the same size as an unsigned int. 这是在32位运行,因此指针的大小与unsigned int相同。

Consider the following code: 请考虑以下代码:

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

This is the output: 这是输出:

f: cccccccc cccccccc  
b: 0 0  
j: cccccccc cccccccc

EDIT: 编辑:
Here is the disassembly I see associated with Bar b; 这是我看到与Bar b;相关的反汇编Bar b; The __autoclassinit2 is zeroing the memory. __autoclassinit2将内存归零。 It is not part of the constructor but rather is zeroed before the constructor call. 它不是构造函数的一部分,而是在构造函数调用之前归零。

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

All your types contain data members that are built-in types, so none of them will be zero-initialized unless you do one of the following (taking the example of Foo ): 您的所有类型都包含内置类型的数据成员,因此除非您执行以下操作之一,否则它们都不会进行零初始化(以Foo为例):

Initialize the members in the default constructor: 初始化默认构造函数中的成员:

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

or non-static data member initializers ( brace-or-equal-initializer ) 或非静态数据成员初始值设定项( 括号或等于初始化程序

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

or leave Foo unchanged, and value initialize the instance 或者保持Foo不变,并且值初始化实例

Foo f{};

Using the original example, I cannot reproduce the result you observe using VS2013, 32-bit Debug build. 使用原始示例,我无法使用VS2013,32位调试版本重现您观察到的结果。 The output I get is 我得到的输出是

f: cccccccc cccccccc
b: cccccccc cccccccc
j: cccccccc cccccccc

EDIT : I am able to reproduce the behavior where b is being zero-initialized. 编辑:我能够重现b被零初始化的行为。 This happens if you enable the /sdl ( Security Development Lifecycle checks ) compiler switch (under Configuration Properties -> C/C++ -> General). 如果启用/sdl安全开发生命周期检查 )编译器开关(在配置属性 - > C / C ++ - >常规下),则会发生这种情况。

From the MSDN documentation for the switch: 从交换机的MSDN文档

When /sdl is enabled, the compiler generates code to perform these checks at run time: 启用/sdl ,编译器会生成代码以在运行时执行这些检查:
... - ...
— Performs class member initialization. - 执行类成员初始化。 Automatically initializes all class members to zero on object instantiation (before the constructor runs) . 在对象实例化时(在构造函数运行之前)自动将所有类成员初始化为零 This helps prevent the use of uninitialized data associated with class members that the constructor does not explicitly initialize. 这有助于防止使用与构造函数未显式初始化的类成员关联的未初始化数据。

This blog post even mentions the __autoclassinit function, although the heuristics he lists don't exactly match what we're observing because the behavior of this feature has changed between VS2012 and VS2013. 这篇博文甚至提到了__autoclassinit函数,尽管他列出的启发式方法并不完全符合我们观察的内容,因为此功能的行为在VS2012和VS2013 之间发生了变化。

Also worth nothing is that the compiler seems to not only distinguish between aggregates ( Foo ) and non-aggregates (the other two), which makes some sense, but, for some truly bizarre reason, it will only perform this zero-initialization if you use the class-key class , and not struct , in the class definition. 同样值得一提的是,编译器似乎不仅区分聚合( Foo )和非聚合(其他两个),这是有道理的,但是,出于一些真正奇怪的原因,它只会执行这种零初始化,如果你在类定义中使用class-key class ,而不是struct

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM