c++ - 在具有引用成员的对象上使用放置 `new` 的结果

标签 c++ constants language-lawyer c++17 placement-new

"Using placement new to update a reference member?"问题显示了这个例子(简化):

struct Foo { int& v_; };

int a, b;
Foo f{a};

new (&f) Foo{b};

assert(&f.v_ == &a); // UB

通过原名访问f肯定是UB as explained by T.C. in the linked question .我知道 std::launder 可以用来解决这个问题:

assert(&std::launder(&f)->v_ == &a); // OK, will fire the assert

但是如何使用放置 new 返回的指针呢?即

auto p = new (&f) Foo{b};    
assert(&(p->v_) == &a); // UB? OK?

在这种情况下,我们不是通过对象的原始名称来引用对象,而是通过 new 返回的任何位置。

这是未定义的行为还是标准允许的?

最佳答案

这个:

auto p = new (&f) Foo{b};    
assert(&(p->v_) == &a); // UB? OK?

定义明确。断言将触发。 new 创建一个新对象,p 指向那个新对象。这一切都很好。我们正在重用 f 的存储,[basic.life] 中有很多规则关于如何使用 old 名称可以和不可以的问题 - 关于如何使用 f 的规则,以前指向 f 的指针, 等等。你不能重用 &f 而不用 launder 对它进行处理。在这种情况下,有关于如何以及何时可以调用析构函数的规则,或者如何为静态存储或 const 对象重用存储 - 这些在这里都不重要。

但是 p 是一个新事物——它只是指代新对象。 p->v_ 是您创建的引用 b 的新 int&。这与 a 不是同一个对象,因此指针比较不相等。

关于c++ - 在具有引用成员的对象上使用放置 `new` 的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52820667/

相关文章:

c++ - 为什么我的字符串打印在错误的地方?

c - 为什么 GCC 给我这个 `-Wdiscarded-qualifiers` 警告?

c++ - 标记所有不修改 const 的变量有什么缺点吗?

c++ - 就序列点而言,前置增量与后增量

c++ - 在具有外部链接的匿名命名空间中声明的实体示例

c++ - 如何从科学记数法切换回来

c++ - 为什么 lambda 在转换为函数指针时不能在 constexpr 上下文中使用?

c++ - 为什么在 const 指针中进行非法结构操作?

c++ - 是否可以在初始化的函数指针声明中使用 `auto` 关键字作为返回类型?

c++ - 不能包含 std::format