rvalue refs和std :: move

drw*_*owe 2 c++ rvalue-reference c++11

有人可以解释为什么B不编译,但C呢?我不明白为什么std :: move是必需的,因为变量已经是rvalue ref.

struct A {
  int x;
  A(int x=0) : x(x) {}
  A(A&& a) : x(a.x) { a.x = 0; }
};

struct B : public A {
  B() {}
  B(B&& b) : A(b) {}  // compile error with g++-4.7
};

struct C : public A {
  C() {}
  C(C&& c) : A(std::move(c)) {}  // ok, but why?
};
Run Code Online (Sandbox Code Playgroud)

How*_*ant 23

在声明中:

B(B&& b)
Run Code Online (Sandbox Code Playgroud)

参数 b使用以下类型声明:rvalue reference to B.

在声明中:

A(b)
Run Code Online (Sandbox Code Playgroud)

表达式 b的类型是一个左值B.

并且左值表达式不能绑定到右值引用:特别是语句中的右值引用:

A(A&& a)
Run Code Online (Sandbox Code Playgroud)

这种逻辑完全遵循语言的其他部分.考虑这个功能:

void
f(B& b1, B b2, B&& b3)
{
   g(b1);
   g(b2);
   g(b3);
}
Run Code Online (Sandbox Code Playgroud)

虽然参数f都与不同类型的表达式申报b1,b2b3有类型的所有左值表达式B,从而将所有调用相同的功能g,无论怎样g过载.

在C++ 11中,区分变量的声明和使用该变量产生的表达式比以往任何时候都更加重要.并且表达式从不具有引用类型.相反,它们的值类别恰好是以下之一:lvalue,xvalue,prvalue.

该声明:

A(std::move(c))
Run Code Online (Sandbox Code Playgroud)

没关系,因为std::move返回一个右值引用.返回rvalue引用的函数调用产生的表达式具有值category:xvalue.与prvalues一起,xvalues被认为是rvalues.和rvalue表达式类型C:

std::move(c)
Run Code Online (Sandbox Code Playgroud)

将结合在右值参考参数:A(A&& a).

我发现下图(最初由Bjarne Stroustrup发明)非常有用:

       expression
          /  \
    glvalue  rvalue
     /  \    /  \
lvalue  xvalue  prvalue
Run Code Online (Sandbox Code Playgroud)


K-b*_*llo 13

因为命名变量不是rvalues,即使声明了&&.如果它有一个名称,那么它不是临时的,因此你需要使用std::move.