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

问题描述 投票:3回答:1

"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作为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返回的任何位置。

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

c++ const language-lawyer c++17 placement-new
1个回答
5
投票

这个:

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

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

p是一个新东西 - 它只是指新的对象。而p->v_是你创造的新的int&,指的是b。这与a不是同一个对象,所以指针比较不相等。

© www.soinside.com 2019 - 2024. All rights reserved.