编写默认构造函数会强制零初始化
Writing a Default Constructor Forces Zero-Initialization?
这些是我的类定义:
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 到 Foo
: Foo() : _ent(0) {}
我的输出变为:
0 0 0
1246382666 1246382666 1246382666
这是正确的行为吗?添加我自己的默认 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,因此尤其如此,因为成员是私有的,您无法更改它。
- 初始化具有非默认构造函数的std::数组项的更好方法
- 有没有一种代码密度较低的方法来使用非默认构造函数初始化数组?
- 副本初始化的默认模板参数推导
- 使用 std::分配器在 constexpr 中进行默认初始化
- 在C++中使用默认构造函数初始化对象的不同方法
- 强制使用默认构造函数对成员进行未初始化的声明
- 使用默认构造函数初始化对象的不同方法
- 在没有默认构造函数时使用垃圾数据初始化对象
- 为什么对象默认初始化,但基元不在C++?
- 默认参数和空列表初始化
- 为什么std::atomic的默认构造函数不默认初始化底层存储值
- C++中未初始化成员布尔变量的默认值是多少?
- 两个成员,在Base中默认初始化,可能在Derived中非默认初始化
- 默认初始化无法正常工作
- 如何用默认值0或-1初始化unordered_set
- C++11 默认类成员初始化与初始值设定项列表同时
- 使用聚合初始化模拟默认函数参数是否存在任何陷阱?
- 初始化在类类型 #define 中定义的非静态成员数组,不带默认 ctor
- 在皮条类中初始化默认值的最佳位置
- 值初始化:默认初始化或零初始化