在具有引用成员的对象上使用放置“new”的结果

Using placement `new`'s result on a object with 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 。我知道 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 的先前指针等的规则。如果没有 launder-ing,则不能重用 &f。在这种情况下,有关于如何以及何时调用析构函数的规则,或者如何为静态存储或 const 对象重用存储 - none 在这里都很重要。

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