c++ 11 VS2013级POD成员初始化。

时间:2023-01-15 17:43:09

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. I believe this is due to some change in C++11, but it could also be an anomaly of the v120 platform toolset.

我找遍了所有的地方,想对此做个解释,但我的答案是简短的。我从VS2013 v120平台工具集看到了这种行为,但是当我将工具集设置为v90 (VS2008工具集)时,一切都是未初始化的。我相信这是由于c++ 11的一些变化,但它也可能是v120平台工具集的一个异常。

Can anyone explain what's going on here on the C++/C++11 level? That is, why is b zeroed out? And why is j not also zeroed out? (i.e. why is the behavior different for structs than for classes)

有人能解释一下c++ / c++ 11级的情况吗?也就是说,为什么b是0 ?为什么j不也是0呢?(即为什么结构的行为与类的不同)

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位上运行的,所以指针与无符号整数的大小相同。

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; The __autoclassinit2 is zeroing the memory. It is not part of the constructor but rather is zeroed before the constructor call.

编辑:这是我看到的与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)  

1 个解决方案

#1


6  

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)

或非静态数据成员初始化器(brace-or- 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. The output I get is

使用最初的示例,我无法复制您使用VS2013, 32位调试构建所观察到的结果。我得到的输出是。

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

EDIT : I am able to reproduce the behavior where b is being zero-initialized. This happens if you enable the /sdl (Security Development Lifecycle checks) compiler switch (under Configuration Properties -> C/C++ -> General).

编辑:我能够复制b为零初始化的行为。如果您启用了/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:
...
— 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.

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

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类,而不是struct,那么它只会执行这个零初始化。

#1


6  

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)

或非静态数据成员初始化器(brace-or- 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. The output I get is

使用最初的示例,我无法复制您使用VS2013, 32位调试构建所观察到的结果。我得到的输出是。

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

EDIT : I am able to reproduce the behavior where b is being zero-initialized. This happens if you enable the /sdl (Security Development Lifecycle checks) compiler switch (under Configuration Properties -> C/C++ -> General).

编辑:我能够复制b为零初始化的行为。如果您启用了/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:
...
— 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.

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

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类,而不是struct,那么它只会执行这个零初始化。