【问题标题】:Can I overwrite a const object via placement-new?我可以通过placement-new 覆盖一个const 对象吗?
【发布时间】:2021-11-15 11:01:54
【问题描述】:

Basic.life/8 告诉我们,我们可以使用对象占用的存储空间在其生命周期结束后创建一个新对象,并使用其原始名称来引用它,除非:

  • 原始对象的类型不是 const 限定的,并且,如果是类类型,则不包含任何类型为 const 限定或引用类型的非静态数据成员,并且 [.. .]

强调我的

但是,就在其下方,我们可以看到一条说明:

  • 如果不满足这些条件,则可以通过调用std​::​launder从表示其存储地址的指针中获得指向新对象的指针

这解释了the purposes of std::launder。我们可以有一个具有const 成员的类类型,并使用placement-new 在其中创建一个具有不同内部值的新对象。

让我吃惊的是第一句话的第一部分。它清楚地表明如果存储是const(不一定包含const成员,但整个对象声明为const),我们不能用它来引用一个新的对象,但它可能暗示std::launder 可能会修复它。

但是我们如何创建这样的对象呢?最简单的例子失败了:

const auto x = 5;
new (&x) auto(10);

这是因为我们不能使用const void* 作为placement-new 的缓冲区。我们可以const_cast 它,但抛弃“真实”constness 是未定义的行为。我相信这里也是如此。

如果只是禁止使用const 对象作为放置新缓冲区,我会理解,但如果是这样的话,第一个引号的强调部分的目的是什么?我们可以将真正的 const 对象的存储重用于不同的对象吗?

【问题讨论】:

  • 如果原始对象是const,如果你修改它是未定义的行为。编译器可能会将这些对象放在只读内存中,或者假设值永远不会改变。如果在第一种情况下您会遇到写访问冲突,而在第二种情况下,编译器可能会使用它在编译时确定的值,因为它有权假设此类对象永远不会更改。

标签: c++ language-lawyer stdlaunder


【解决方案1】:

显然,只需在我链接到的标准部分下方查看 2 个项目。 Basic.life/10 告诉我们:

在具有静态、线程或自动存储持续时间的 const 完整对象占用的存储空间内,或在此类 const 对象在其生命周期结束之前曾经占用的存储空间内创建新对象,会导致未定义的行为。

并附带一个例子:

struct B {
  B();
  ~B();
};

const B b;

void h() {
  b.~B();
  new (const_cast<B*>(&b)) const B;     // undefined behavior
}

这最终让我得出一个结论:在真正的 const 对象占用的内存上使用 placement-new 是非法的。因此,我认为问题中提到的注释(参考点8)是错误的 - 它应该排除有问题的情况。

【讨论】:

    【解决方案2】:

    一个 const 对象可以有指向其位置的非 const 指针。

    struct bar{ int x=5; };
    struct foo{
      const bar b;
    };
    foo f;
    ::new (&f) foo{{3}};
    

    这里我有一个 const int f.b.x 我销毁并构造一个值为 3 的新的。

    char buff[sizeof(foo)];
    foo const* pf=::new(buff)foo;
    foo const* pf2=::new(buff)foo{{3}};
    

    也许也可以通过工会来做到这一点。

    【讨论】:

    • 这个例子没有引用强调的引用。它指的是下一部分,它提到了一个类类型,它包含一个类型为 const 限定的非静态数据成员。将f 设为const foo,代码无法编译。这就是我要问的。如果我让自己不清楚,我可以要求对我的答案进行编辑以使其更清楚吗?
    • 同一个地址现在有一个常量栏。类型已更改。还添加了一个新的展示位置。核心是 const 对象存储可以有一个指向其内存的非 const 指针。
    猜你喜欢
    • 2013-03-25
    • 2018-06-06
    • 2015-10-17
    • 1970-01-01
    • 2018-05-13
    • 2015-01-23
    • 1970-01-01
    • 2014-08-07
    • 2013-05-11
    相关资源
    最近更新 更多