"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/