为什么在变量中存储右值引用会导致它悬挂

时间:2016-10-15 14:55:21

标签: c++ rvalue-reference

我有一个抽象基类和一些具体的子类:

class AbstractBaseClass {
private:
  bool destructed {};
public:
  virtual ~AbstractBaseClass() { destructed = true; }
  // returns false unless we're calling on already destructed value
  bool leaked() { return destructed; };
};

class ConcreteSubClassA : public AbstractBaseClass {
public:
  ~ConcreteSubClassA() override {}
};
class ConcreteSubClassB : public AbstractBaseClass {
public:
  ~ConcreteSubClassB() override {}
};

有人可以向我解释为什么rvalue引用了子类实例 在这些情况下不会泄漏:

static_cast<AbstractBaseClass&&>(ConcreteSubClassA()).leaked(); // false

std::forward<AbstractBaseClass>(ConcreteSubClassA()).leaked(); // false

((rand() & 1)
 ? static_cast<AbstractBaseClass&&>(ConcreteSubClassA())
 : static_cast<AbstractBaseClass&&>(ConcreteSubClassB())
).leaked(); // false

((rand() & 1)
 ? std::forward<AbstractBaseClass>(ConcreteSubClassA())
 : std::forward<AbstractBaseClass>(ConcreteSubClassB())
).leaked(); // false

AbstractBaseClass&& abc = ConcreteSubClassA();
abc.leaked(); // false

AbstractBaseClass&& abc = static_cast<AbstractBaseClass&&>(ConcreteSubClassA());
abc.leaked(); // false

但这些呢?

AbstractBaseClass&& abc = std::forward<AbstractBaseClass>(ConcreteSubClassA());
abc.leaked(); // true

AbstractBaseClass&& abc = (rand() & 1) 
  ? static_cast<AbstractBaseClass&&>(ConcreteSubClassA())
  : static_cast<AbstractBaseClass&&>(ConcreteSubClassB());
abc.leaked(); // true

AbstractBaseClass&& abc = (rand() & 1) 
  ? std::forward<AbstractBaseClass>(ConcreteSubClassA())
  : std::forward<AbstractBaseClass>(ConcreteSubClassB());
abc.leaked(); // true

那就是为什么这么早地调用析构函数?

1 个答案:

答案 0 :(得分:3)

临时表在完整表达式结束时被销毁(除非绑定到引用时)。这个事实解释了犯罪工作的直接用途。

将临时对象直接绑定到引用(即const&&&)时,其生命周期会延长以匹配生命周期参考资料。这就是您的示例直接(或通过强制转换)绑定到右值工作的原因。

当将左值绑定到参考生命周期时,得到扩展 - 编译器不能期望透视该构造。 确实将左值转换为右值引用。请注意,右值引用是左值。

当然,返回leaked()true的结果取决于未定义的行为:在对象被销毁时,您无法调用它而不会调用未定义的行为。