3

以下代码在 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);
}

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

4

2 回答 2

9

这是完全无效的。

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

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

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

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

[基本生活]/7:

如果在对象的生命周期结束之后,在对象占用的存储空间被重用或释放之前,在原始对象占用的存储位置创建一个新对象,一个指向原始对象的指针,一个指向原始对象的引用引用原始对象,或者原始对象的名称将自动引用新对象,并且一旦新对象的生命周期开始,可用于操作新对象,如果:

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

由于不满足第三个要点,在调用 之后Barf不会引用由放置创建的对象new,而是指向先前存在的不再存在的对象,并且尝试使用它会导致未定义的行为。

另见CWG1776P0137R0

于 2015-11-04T06:30:52.737 回答
0

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

基本上,不要那样做。

于 2015-11-04T06:13:16.280 回答