【问题标题】:Does C++ default-initialization preserve prior zero-initialization?C++ 默认初始化是否保留先前的零初始化?
【发布时间】:2016-02-01 01:38:47
【问题描述】:

如果具有静态存储持续时间的对象的 C++ 构造函数未初始化成员,是否需要保留先前的零初始化,或者它是否使成员具有不确定的值?

我对 C++ 规范的解读是它自相矛盾。

例子:

#include <iostream>

struct Foo { Foo(); int x; } object;

Foo::Foo() { }

int main() { std::cout << object.x << std::endl; }

Foo() 构造函数没有显式初始化成员 object.x,所以 根据 12.6.2 第 8 段中的说明:

该成员具有不确定的价值。

但是通过各种初始化的细节,这似乎 不正确。成员 object.x 是零初始化的,因为它具有静态存储持续时间,然后我看不到任何改变它的东西。

关于构造函数,12.6.2中适用的文字是:

实体是默认初始化的。

在8.5第7段中,默认初始化的相关案例是:

...不执行初始化

我读到的意思是默认初始化不会更改先前的零初始化。

我是否遗漏了一些在构造函数调用开始时将所有成员重置为“不确定值”的其他文本?

我在 stackoverflow 上发现了有关零初始化和 默认初始化,但我看不到任何 分析了默认初始化之后会发生什么 同一实体的一些早期初始化。

在这种情况下,可能没有实际效果。但是在一个更复杂的构造函数中,一些成员初始化而其他成员没有,编译器是否必须准确跟踪哪些字节/位被初始化?或者它可以只初始化整个对象(例如,将构造函数简化为 memset() 调用)?

【问题讨论】:

  • 我删除了我的答案,因为我不确定:Foo 是一个具有非平凡初始化的对象,这意味着它的生命周期只有在其构造函数完成后才开始。那么,我不确定其成员的价值观。在构造函数开始执行之前,您甚至可能无法访问它们(通过规范规则),所以我很难知道它们在那个时候存储了值(零)......更不用说第一个对象的存在了地点。
  • @LightnessRacesinOrbit re“嗯,不,如果它只是在草案中,那么它不在标准中,不应该被依赖”..那么我们很难编写大多数真实世界的代码,我认为.鉴于有多少缺陷报告(一些仍处于打开状态)试图修复标准中的错误 :) 例如,open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#191
  • @ᐅJohannesSchaub-litbᐊ 实际上,我认为您删除的答案是一个很好的答案。如果在构造函数调用之前静态存储持续时间对象完全不存在,我很难理解零初始化。例如,编译器在后台将“object”替换为由“new Foo()”初始化的隐藏指针是否有效?
  • @Johannes:我同意;真是一团糟!
  • @user1998586 我更倾向于这没关系。 12.6.2p6 还说如果成员未初始化,则该值是不确定的。但它并没有说没有被构造函数初始化。零初始化也很重要,所以这些不会冲突,IMO。

标签: c++ constructor language-lawyer storage-duration


【解决方案1】:

Defect report 1787 导致N3914 中记录的更改为applied to the draft standard for C++14。哪个更改 [dcl.init] 第 12 段:

如果没有为对象指定初始化器,则该对象是 默认初始化;如果不执行初始化,则对象 自动或动态存储期限具有不确定的价值。 [ 笔记: 具有静态或线程存储持续时间的对象是零初始化的, 见 3.6.2。 ——尾注]

到:

如果没有为对象指定初始化器,则该对象是 默认初始化。 当使用自动或 获取动态存储时长,对象有一个不确定的 值,并且如果没有对对象执行初始化,则 对象保留一个不确定的值,直到该值被替换 (5.17 [expr.ass])。 [注意:具有静态或线程存储的对象 持续时间是零初始化的,见 3.6.2 [basic.start.init]。 -结尾 注意] 如果评估产生不确定的值,则 行为未定义,但以下情况除外:

[...]

这明确了不确定值的情况只发生在自动或动态存储期限的对象上。由于这是通过缺陷报告应用的,它可能也适用于 C++11,因为缺陷报告发生在 C++14 被接受之前,但它也可以进一步应用。关于缺陷应该应用多远的规则我从来都不清楚。

由于在 cmets 中提出了新位置,因此同样的更改也修改了部分 [expr.new],使不确定值部分成为注释:

如果省略 new-initializer,则对象默认初始化 (8.5 [dcl.init]);如果。 [注意:如果不执行初始化,则 对象具有不确定的值。 ——尾注]

该部分的开头说:

[...]由 new-expression 创建的实体具有动态存储 持续时间(3.7.4)。[...]

这似乎足以应用 [dcl.init] 部分中的更改。

此更改也很有趣,因为在此更改之前,C++ 标准中的术语 indeterminate value was not defined

【讨论】:

  • 在这种情况下,新的措辞非常明确。对于放置新的位置(存储持续时间适用的规则?)还不是很清楚。我的阅读是任何先前的初始化都是无关紧要的,并且行为是根据自动/动态存储持续时间。例如,如果你有一个静态持续时间的char数组,然后调用placement-new在数组中构造一个对象,那么char数组的零初始化就无关紧要了吗?
猜你喜欢
  • 2014-12-29
  • 2021-11-11
  • 2020-02-08
  • 2015-03-22
  • 1970-01-01
  • 2010-12-09
  • 1970-01-01
相关资源
最近更新 更多