【问题标题】:Is previously initialize memory guaranteed to persist after a placement new call?以前初始化内存是否保证在放置新调用后持续存在?
【发布时间】:2012-07-30 21:07:38
【问题描述】:

假设我有以下内容:

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 不是值初始化的,第二个断言是否保证保持?逻辑上是应该的,因为内存没有被覆盖,但是是标准规定的吗?

【问题讨论】:

  • 你在同一个内存上创建了两次对象。
  • 我敢说这是未定义的行为,因为第一个对象的生命周期还没有结束。但这可能可以通过调用 dtor 来解决。
  • @pmr:实际上行为并没有很好地定义,因为对象是一个 POD
  • 问的时候我什至没有想到这一点,但我想我做到了,因为 POD 准确地表达了我的想法:)
  • @pmr: 3.8/1 类型 T 的对象的生命周期在以下情况下结束: — 如果 T 是具有非平凡析构函数(12.4)的类类型,则析构函数调用开始,或 — 对象占用的存储空间被重用或释放。 [作为对您在现已删除的答案中引用的请求的回答]

标签: c++ c++11 placement-new


【解决方案1】:

没有。

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

[...] T 类型对象的生命周期在以下情况下结束:

  • 如果 T 是具有非平凡析构函数的类类型(第 12.4 节),则析构函数调用开始,或者
  • 对象占用的存储空间被重用或释放。

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

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

  • [...]

  • 否则,不执行初始化。

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

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

  • 如果省略 new-initializer,则对象为 default-initialized(第 8.5 节);如果不执行初始化, 该对象具有不确定的值。

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

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

【讨论】:

  • 我相信问题是没有初始化是否意味着保证不修改内存。因为正在使用放置 new,所以他想知道他是否可以依赖在构造新对象后未修改的值。
  • @DavidRodríguez-dribeas 我认为“不确定值”很明显,您不能依赖它。
  • 我认为这里的歧义在于“不确定”这个词,它从未真正定义过。它的意思是“始终认为未初始化”,还是表示“认为未初始化,除非先前已初始化”?我们知道使用 uninitialized 值是未定义的行为,但它并没有说明使用 indeterminate 值。
  • @GManNickG 即使不是UB,也不能保证assert通过。 FWIW(可能不多)第 17.6.3.4 节还有一条注释说“涉及不确定值的操作可能导致未定义的行为。”更具体地说,我相信在这些情况下允许实现写入特殊值,例如用于调试。
  • @VladLazarenko 问题是确切地这是否由标准保证。我不明白你想说什么。
猜你喜欢
  • 2017-08-17
  • 2014-01-30
  • 1970-01-01
  • 2013-04-24
  • 2010-09-08
  • 1970-01-01
  • 1970-01-01
  • 2016-04-19
  • 2015-10-01
相关资源
最近更新 更多