先前初始化的内存是否保证在放置新调用后仍然存在?

Is previously initialize memory guaranteed to persist after a placement new call?

提问人:Luchian Grigore 提问时间:7/31/2012 更新时间:7/31/2012 访问量:192

问:

假设我有以下内容:

struct A
{
   int x;
};

//...
A* aOriginal = new A();  //value construct aOriginal
assert( aOriginal->x == 0 );

A* aSecond = new (aOriginal) A;
assert( aSecond->x == 0 );

第二个断言是否保证成立,即使没有初始化值?从逻辑上讲,它应该,因为内存没有被覆盖,但它是由标准指定的吗?aSecond

C++ C++11 放置-新

评论

0赞 yuri kilochek 7/31/2012
您在同一内存上创建对象两次。
0赞 pmr 7/31/2012
无论如何,我敢说这是未定义的行为,因为第一个对象的生存期尚未结束。但这可能可以通过调用 dtor 来解决。
0赞 David Rodríguez - dribeas 7/31/2012
@pmr:实际上,由于对象是 POD,因此行为定义不明确
0赞 Luchian Grigore 7/31/2012
问的时候我什至没有想到这一点,但我想我搞定了,因为 POD 准确地表达了我的想法:)
3赞 David Rodríguez - dribeas 7/31/2012
@pmr:3.8/1 T 类型对象的生存期在以下情况下结束: — 如果 T 是具有非平凡析构函数 (12.4) 的类类型,则析构函数调用将开始,或者 — 对象占用的存储被重用或释放。 [作为对现已删除的答案中报价请求的回答]

答:

9赞 R. Martinho Fernandes 7/31/2012 #1

不。

在同一存储位置构造第二个对象时,前一个对象的生存期结束 (§3.8/1):

[...]在以下情况下,该类型的对象的生存期结束:T

  • 如果是具有非平凡析构函数 (§12.4) 的类类型,则析构函数调用将启动,或者T
  • 对象占用的存储被重用或释放。

创建第二个对象时,由于具有隐式默认构造函数,因此该成员是默认初始化的,因此不执行初始化 (§8.5/6):Ax

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

  • [...]

  • 否则,不执行初始化。

这意味着对象具有不确定的值 (§5.3.4/15):

创建类型对象的 new-expression 将初始化该对象,如下所示:T

  • 如果省略 new-initializer,则对象默认初始化 (§8.5);如果未执行初始化, 对象具有不确定的值。

如果您认为该值不是不确定的,因为您之前在该存储位置上初始化了另一个对象:标准也放弃了这种可能性,因为它说前一个对象的属性在其生命周期结束后不再适用 (§3.8/3):

本国际标准中赋予对象的属性仅适用于给定对象在其生命周期内。

评论

1赞 David Rodríguez - dribeas 7/31/2012
我认为问题在于,不初始化是否意味着内存保证不会被修改。由于正在使用 placement new,因此他想知道是否可以依赖在构造新对象后未修改的值。
2赞 R. Martinho Fernandes 7/31/2012
@DavidRodríguez,我认为“不确定的价值”很清楚,你不能依赖它。
1赞 GManNickG 7/31/2012
我认为这里的歧义在于“不确定”这个词,它从未真正定义过。它的意思是“始终被认为是未初始化的”,还是意味着“除非以前初始化,否则被认为是未初始化的”?我们知道使用未初始化的值是定义的行为,但它没有说明使用不确定的值。
1赞 R. Martinho Fernandes 7/31/2012
@GManNickG即使它不是 UB,也不能保证断言通过。FWIW(可能不多):§17.6.3.4 上还有一条注释,说“涉及不确定值的操作可能会导致未定义的行为。更具体地说,我相信在这些情况下,允许实现写入特殊值,例如用于调试。
2赞 R. Martinho Fernandes 7/31/2012
@VladLazarenko问题在于这是否得到标准保证。我不明白你在那里想说什么。