【发布时间】: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