rence3 = rvalue(); // ok
A &&rvalue_reference4 = const_rvalue(); // error
// 规则四:const右值引用可绑定到const右值和非const右值,不能绑定到左值
const A &&const_rvalue_reference1 = lvalue; // error
const A &&const_rvalue_reference2 = const_lvalue; // error
const A &&const_rvalue_reference3 = rvalue(); // ok
const A &&const_rvalue_reference4 = const_rvalue(); // ok
// 规则五:函数类型例外
void fun() {}
typedef decltype(fun) FUN; // typedef void FUN();
FUN & lvalue_reference_to_fun = fun; // ok
const FUN & const_lvalue_reference_to_fun = fun; // ok
FUN && rvalue_reference_to_fun = fun; // ok
const FUN && const_rvalue_reference_to_fun = fun; // ok
【说明】:(1) 一些支持右值引用但版本较低的编译器可能会允许右值引用绑定到左值,例如g++4.4.4就允许,但g++4.6.3就不允许了,clang++3.2也不允许,据说VS2010 beta版允许,正式版就不允许了,本人无VS2010环境,没测试过。
(2)右值引用绑定到字面值常量同样符合上述规则,例如:int &&rr = 123;,这里的字面值123虽然被称为常量,可它的类型为int,而不是const int。对此C++03标准文档4.4.1节及其脚注中有如下说明:
If T is a non-class type, the type of the rvalue is the cv-unqualified version of T.
In C++ class rvalues can have cv-qualified types (because they are objects). This differs from ISO C, in which non-lvalues never have cv-qualified types.
因此123是非const右值,int &&rr = 123;语句符合上述规则三。
此,我们已经了解了不少右值引用的知识点了,下面给出了一个完整地利用右值引用实现move语意的例子:
#include
#include
#define PRINT(msg) do { std::cout << msg << std::endl; } while(0) template
struct remove_reference {typedef _Tp type;}; template
struct remove_reference<_Tp&> {typedef _Tp type;}; template
struct remove_reference<_Tp&&> {typedef _Tp type;}; template
inline typename remove_reference<_Tp>::type&& move(_Tp&& __t) { typedef typename remove_reference<_Tp>::type _Up; return static_cast<_Up&&>(__t); } class A { public: A(const char *pstr) { PRINT("constructor"); m_data = (pstr != 0 ? strcpy(new char[strlen(pstr) + 1], pstr) : 0); } A(const A &a) { PRINT("copy constructor"); m_data = (a.m_data != 0 ? strcpy(new char[strlen(a.m_data) + 1], a.m_data) : 0); } A &operator =(const A &a) { PRINT("copy assigment"); if (this != &a) { delete [] m_data; m_data = (a.m_data != 0 ? strcpy(new char[strlen(a.m_data) + 1], a.m_data) : 0); } return *this; } A(A &&a) : m_data(a.m_data) { PRINT("move constructor"); a.m_data = 0; } A & operator = (A &&a) { PRINT("move assigment"); if (this != &a) { m_data = a.m_data; a.m_data = 0; } return *this; } ~A() { PRINT("destructor"); delete [] m_data; } private: char * m_data; }; void swap(A &a, A &b) { A tmp(move(a)); a = move(b); b = move(tmp); } int main(int argc, char **argv, char **env) { A a("123"), b("456"); swap(a, b); return 0; }
输出结果为:
constructor
constructor
move constructor
move assigment
move assigment
destructor
destructor
destructor