本文为第三部分,目录请参阅概述部分:http://www.cnblogs.com/harrywong/p/4220233.html。
右值引用
如果x是任意类型,那么x&&则被称作一个对x的右值引用(rvalue reference)。为了更好区分,原来的引用x&现在也被称作左值引用(lvalue reference)。
一个右值引用是一种同原始引用x&的行为非常类似的类型,但是有一些特例。最重要的一个就是当面临方法重载决议的时候,左值倾向于旧式的左值引用,而右值偏向于新的右值引用。
void foo(X& x); // 左值引用重载 void foo(X&& x); // 右值引用重载 X x; X foobar(); foo(x); // 参数是左值,调用 foo(X&) foo(foobar()); // 参数是右值,调用 foo(X&&)
所以它的要点在于:
右值引用允许一个方法在编译时通过重载决议做出选择,基于:”我是被一个左值还是右值调用?“
你可以基于此规则重载任何方法,就像如下所示。但是在绝大多数情况下,这种形式的重载应该只出现在拷贝构造函数和赋值操作符中,为了实现Move语义。
X& X::operator=(X const & rhs); // 常规的实现 X& X::operator=(X&& rhs) { // Move语义,交换this和rhs的内容 return *this; }
实现一个基于右值引用的拷贝构造函数的重载也是类似的。
要点:通常第一眼看上去正确的其实依然有些小瑕疵,这在C++中是经常发生的。事实证明,在某些情况下,在上面对拷贝赋值操作符的实现中,将this和rhs的内容简单的交换,并没有足够好。我们将在第四节「强制Move语义」中继续讨论这个问题。
备注:如果你实现
void foo(X&);
而不是
void foo(X&&);
那么当然行为表现并没有改变:
foo
可以被左值调用,但是不能被右值调用。如果你实现
void foo(X const &);
而不是
void foo(X&&);
那么依然,行为表现依然没有变化,
foo
可以被左值和右值调用,但是想要区分左值和右值是不可能的。这一点只有在如下实现情况下才可行
void foo(X&&);
同样的,最后如果你实现
void foo(X&&(;
但是既不是
void foo(X&);
和
void foo(X const &);
那么,根据最终版本的C++11,
foo
可以被右值调用,但是如果试着用一个左值去调用它的话,将会触发一个编译器错误。