编写默认构造函数会强制零初始化

Writing a Default Constructor Forces Zero-Initialization?

本文关键字:初始化 默认 构造函数      更新时间:2023-10-16

这些是我的类定义:

class Foo{
    int _ent;
public:
    void printEnt() const{cout << _ent << ' ';}
};
class Bar{
    Foo _foo;
public:
    void printEnt() const{_foo.printEnt();}
};

这是我的测试代码:

char* buf = new char[sizeof(Foo) + sizeof(Foo) + sizeof(Bar)];
fill(buf, buf + sizeof(Foo) + sizeof(Foo) + sizeof(Bar), 'J');
cout << ((int*)buf)[0] << ' ' << ((int*)buf)[1] << ' ' << ((int*)buf)[2] << endl;
Foo* first = new (buf) Foo;
Foo* second = new (buf + sizeof(Foo)) Foo();
Bar* third = new (buf + sizeof(Foo) * 2) Bar;
first->printEnt(); second->printEnt(); third->printEnt();

我的输出是:


1246382666 1246382666 1246382666 1246382666 0 1246382666

但是如果我添加一个public默认 ctor 到 FooFoo() : _ent(0) {}

我的输出变为:


1246382666 1246382666 1246382666

0 0 0

这是正确的行为吗?添加我自己的默认 ctor 是否应该消除默认初始化的可能性?

如果重要的话,我正在 gcc 4.8.1 上运行这段代码。结果应该是可靠的,因为我正在运行调试并断言: assert(sizeof(Foo) == sizeof(int) && sizeof(Bar) == sizeof(int));

一旦为类型提供了构造函数,它将始终是调用,用于默认初始化和值初始化。 这是语言的基本原则。所以一旦你定义了Foo::Foo(),它就会在任何时候被调用构建Foo;如果有默认构造函数,它将是调用,即使在默认初始化的情况下也是如此。 所以您看到的行为是正确的。

编辑:

默认初始化解释 §8.5/7,特别是:

默认初始化 T 类型的对象意味着:

— 如果 T 是(可能符合 cv 条件的(类类型(条款 9(,则调用 T 的默认构造函数 (12.1( [...]

在您的情况下,您可能还想看看如何如果未提供任何构造函数,编译器将生成默认构造函数,§12.1/4;特别是,生成的默认构造函数调用任何基类或成员的默认构造函数。

值初始化在 §8.5/8 中。 它基本上是默认的初始化之前是零初始化,因此默认不执行任何操作的初始化仍然会找到所有内容零初始化。

然而,更根本的是:在这种情况下,一个非常基本的涉及C++原则,可追溯到第一个之前很久标准:如果为对象提供构造函数,它将被使用。 无需进行各种奇怪的指针投射,它如果没有正确,就不可能获得对象构建。 该标准描述了这种情况是如何发生的,并涵盖还有很多其他特殊情况,但基本原则是从一开始就在那里(以及任何会导致它不在标准中得到尊重注定要失败(。

您的问题已在标准的 C++11 修订版中得到解答:

class Foo{
    int _ent=0;
public:
    // ...
};

如果随后定义自己的默认构造函数,则成员仍将初始化为其默认值,即使默认构造函数未显式执行此操作也是如此。

当您提供默认构造函数时,您将不再获得编译器生成的构造函数。 由于默认构造函数将成员初始化为 0,因此成员将始终为 0,因此尤其如此,因为成员是私有的,您无法更改它。