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

Vit*_*meo 3 c++ const placement-new language-lawyer c++17

"使用放置新更新基准部件?" 问题显示了这个例子(简化):

struct Foo { int& v_; };

int a, b;
Foo f{a};

new (&f) Foo{b};

assert(&f.v_ == &a); // UB
Run Code Online (Sandbox Code Playgroud)

f通过其原始名称访问肯定是UB,正如TC在链接问题中解释的那样.我知道std::launder可以用来解决这个问题:

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

但是使用放置返回的指针怎么样new?即

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

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

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

Bar*_*rry 5

这个:

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

定义明确.断言将触发.new创建一个新对象,并p指向该新对象.这一切都很好.我们正在重复使用f存储,[basic.life]中有很多关于什么是好的规则,而不是关于如何使用名称的规则 - 有关于如何使用的规则f,以前的指针f等等&f没有launder它你就无法重复使用.有关在这种情况下如何以及何时可以调用析构函数的规则,或者如何重用存储用于静态存储或const对象 - 这些都不重要.

但这p是一个新事物 - 它只是指新对象.并且p->v_int&您创建的新内容b.这不是同一个对象a,因此指针比较不相等.