使用placement new来更新引用成员?

时间:2015-11-04 06:06:46

标签: c++ reference object-lifetime placement-new reference-binding

以下代码在C ++中是否合法?

template<typename T>
class Foo {
public:
    Foo(T& v) : v_(v) {}

private:
    T& v_;
};

int a = 10;
Foo<int> f(a);

void Bar(int& a) {
    new (&f)Foo<int>(a);
}

引用不应该绑定两次,对吧?

2 个答案:

答案 0 :(得分:9)

这完全无效。

[basic.life] / 1,强调我的:

  

类型T的对象的生命周期在以下时间结束:

     
      
  • 如果T是具有非平凡析构函数(12.4)的类类型,则析构函数调用将启动,或者
  •   
  • 对象占用的存储空间被重用或释放。
  •   

placement new重用存储,结束由f表示的对象的生命周期。

[basic.life] / 7:

  

如果在对象的生命周期结束之后和存储之前   对象占用的是重用或释放的,一个新的对象是   在原始对象占用的存储位置创建,a   指向原始对象的指针,引用的引用   到原始对象,或原始对象的名称   自动引用新对象,一旦生命周期   新对象已启动,可用于操作新对象,如果:

     
      
  • 新对象的存储空间正好覆盖原始对象占用的存储位置,
  •   
  • 新对象与原始对象的类型相同(忽略顶级cv限定符),
  •   
  • 原始对象的类型不是const限定的,如果是类类型,则不包含任何类型为的非静态数据成员   const限定或引用类型
  •   
  • 原始对象是类型为T的派生程度最高的对象(1.8),新对象是类型为T的派生程度最高的对象(即它们是   不是基类子对象)。
  •   

由于第三个项目符号点不满意,在致电Bar后,f并未引用展示位置new创建的对象,而是不再涉及之前存在的生物对象,并且试图使用它会导致未定义的行为。

另请参阅CWG1776P0137R0

答案 1 :(得分:0)

这可能是合法的,但它的风格非常糟糕。放置new的参数是void *,所以你告诉C ++将f的地址重新解释为一个void *,然后用它作为构造新东西的位置 - 覆盖原始的f。

基本上,不要这样做。