35

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

#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

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

4

2 回答 2

50

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

所以当你初始化时:

Type x;

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

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

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

同样适用于:

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

如果你定义了构造函数

X::X() {}

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

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

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

new int;

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

new int();

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

Type x();

由于语法歧义,不允许使用

Type x = Type();

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

C++11 引入了新的语法,

Type x{};

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

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

于 2011-02-08T12:19:13.513 回答
18

简短的回答是:空括号执行值初始化

当你说Container *pc = new Container;相反时,你会观察到不同的行为。

于 2011-02-08T12:19:40.730 回答