右值引用和局部变量的移动

Luk*_*ker 5 c++ move rvalue-reference move-semantics

在此代码段中,我分配了一个本地对象B,该本地对象B传递给另一个对象C的构造函数,该对象将其作为右值引用。然后,我将后者放入容器中。

当我检索C并将static_cast的成员返回给B时,该值不正确(并且valgrind标识18个错误!)

#include <iostream>
#include <memory>
#include <vector>

class A {
public:
  virtual ~A() {};
};

class B: public A {
public:
  B(int foo) : _foo(foo) {}
  int _foo;
};

class C {
public:
  C(A&& a): _a(std::move(a)) {}
  A&& _a;
};

std::vector<C> v;

void bar() {
  v.emplace_back(B(12));
}

int main() {
  bar();
  C&& c = std::move(v.front());
  std::cout << static_cast<B&&>(c._a)._foo << std::endl;
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我的理解是,由于C采用右值引用,因此不应有任何对象切片。我仍然应该能够检索完整的B对象。另外,我的理解(很可能是有缺陷的)std::move是,我可以将局部变量“移出”其上下文,并且通过引用右值引用,C可以拥有B的所有权。

输出是39931504而不是12

任何人都可以向我解释发生了什么事?

bip*_*pll 2

我应该仍然能够检索完整的 B 对象。

如果它不是一个在 control 到达右大括号时不存在的临时变量,那么您就会这样做bar。您在您的文件中保存了一个引用C,并且对临时对象的引用很快就会变得悬空。

一个快速解决方法是简单地将C的成员声明更改为std::unique_ptr<A> a;并正确初始化它,例如

template<class AChild> C(AChild child)
  : a(std::make_unique<AChild>(std::move(child))) {};
Run Code Online (Sandbox Code Playgroud)

(根据口味添加 SFINAE)。

  • 由于OP似乎想要“B”的多态行为,因此将成员变成“std::unique_ptr&lt;A&gt;”似乎更合适。 (2认同)