为什么在堆中创建对象或堆栈中的临时对象时,隐式构造函数将结构中的 POD 初始化为零?

标准和 C++ 书说,类类型成员的默认构造函数由隐式生成的默认构造函数调用,但内置类型未初始化.但是,在这个测试程序中,在堆中分配对象或使用临时对象时,我得到了意想不到的结果:

The standard and the C++ book say that the default constructor for class type members is called by the implicit generated default constructor, but built-in types are not initialized. However, in this test program I get unexpected results when allocating an object in the heap or when using a temporary object:

#include<iostream>


struct Container
{
    int n;
};

int main()
{
    Container c;
    std::cout << "[STACK] Num: " << c.n << std::endl;

    Container *pc = new Container();
    std::cout << "[HEAP]  Num: " << pc->n << std::endl;
    delete pc;

    Container tc = Container();
    std::cout << "[TEMP]  Num: " << tc.n << std::endl;

}

我得到这个输出:

[STACK] Num: -1079504552
[HEAP]  Num: 0
[TEMP]  Num: 0

这是编译器特有的行为吗?我真的不打算依赖这个,但我很想知道为什么会发生这种情况,特别是对于第三种情况.

Is this some compiler specific behaviour? I don't really intend to rely on this, but I'm curious to know why this happens, specially for the third case.

推荐答案

这是预期的行为.有两个概念,默认初始化"和值初始化".如果您不提及任何初始化程序,则该对象是默认初始化的",而如果您确实提及它,即使是默认构造函数的 (),该对象也是已初始化的值".定义构造函数时,两种情况都调用默认构造函数.但是对于内置类型,值初始化"会将内存归零,而默认初始化"则不会.

It's expected behaviour. There are two concepts, "default initialization" and "value initialization". If you don't mention any initializer, the object is "default initialized", while if you do mention it, even as () for default constructor, the object is "value initialized". When constructor is defined, both cases call default constructor. But for built-in types, "value initialization" zeroes the memory whereas "default initialization" does not.

所以当你初始化时:

Type x;

如果提供了默认构造函数,它将调用默认构造函数,但原始类型将未初始化.但是,当您提到初始化程序时,例如

it will call default constructor if one is provided, but primitive types will be uninitialized. However when you mention an initializer, e.g.

Type x = {}; // only works for struct/class without constructor
Type x = Type();
Type x{}; // C++11 only

原始类型(或结构的原始成员)将被 VALUE 初始化.

a primitive type (or primitive members of a structure) will be VALUE-initialized.

同样适用于:

struct X { int x; X(); };

如果你定义了构造函数

X::X() {}

x 成员将未初始化,但如果你定义了构造函数

the x member will be uninitialized, but if you define the constructor

X::X() : x() {}

它将被 VALUE 初始化.这也适用于 new,所以

it will be VALUE-initialized. That applies to new as well, so

new int;

应该给你未初始化的内存,但是

should give you uninitialized memory, but

new int();

应该给你初始化为零的内存.不幸的是语法:

should give you memory initialized to zero. Unfortunately the syntax:

Type x();

由于语法歧义而不允许

Type x = Type();

必须调用默认构造函数后跟复制构造函数,如果它们都被指定且不可内联.

is obliged to call default constructor followed by copy-constructor if they are both specified and non-inlineable.

C++11 引入了新语法,

C++11 introduces new syntax,

Type x{};

这两种情况都可以使用.如果您仍然坚持使用旧标准,这就是 Boost.ValueInitialized 的原因,因此您可以正确初始化模板参数的实例.

which is usable for both cases. If you are still stuck with older standard, that's why there is Boost.ValueInitialized, so you can properly initialize instance of template argument.

可以找到更详细的讨论,例如在 Boost.ValueInitialized 文档中.

More detailed discussion can be found e.g. in Boost.ValueInitialized documentation.

相关文章