int &&i = 1; //i绑定到了右值1 int b = 2; cout << i << endl; //输出1 i = b; cout << i << endl; //输出2
为了支持移动操作(包括转移构造函数和转移赋值函数),C++引入了一种新的引用类型——右值引用,使用右值引用的代码可以自由的接管所引用对象的内容。
左值引用绑定的是返回左值引用的函数、赋值、下标、解引用、前置递增递减;右值只能绑定到临时对象,所引用的对象将要销毁或该对象没有其他用户。
初始化时,右值引用一定要用一个右值表达式绑定;初始化之后,可以用左值表达式修改右值引用的所引用临时对象的值
int &&temp = 0; int &&i = temp;
temp是一个右值引用变量,变量是左值,因此i引用temp左值是非法的
int &&temp = 0; int &&i = 1; i = temp;
取出temp所引用临时对象的值,再赋值给i所引用临时对象的值。
class A{ public: int b; int a; char c[256]; }; void f(A a) { ; } int main(int argc, char const *argv[]) { A &&a = A(); f(a); }
生成a引用临时对象的一个副本,再传入副本对象的地址。如果f函数的形参是引用类型的,那么调用f函数传入的是a引用对象的地址,而不会生成副本
总结:
- 右值引用,是对临时对象的一种引用,它是在初始化时完成引用的,但是右值引用不代表引用临时对象后就不能改变右值引用所引用对象的值,仍然可以在初始化后改变临时对象的值。
- 对于引用类型,可以用于它所引用对象类型的可以用的地方(把它当成普通变量),只不过用到的值是它所引用的对象的值,它还可以用于移动构造或赋值函数的地方。
class A{ char *p; public: A(char *str){p = new char[strlen(str)+1]; strcpy(p , str);} A(const A& x){p = new char[strlen(x.p)+1]; strcpy(p , x.p);} ~A(){delete []p; p = NULL;} A& operator=(const A& x){ if(&x==this) return *this; delete []p; p = new char[strlen(x.p)+1]; strcpy(p , x.p); return *this; } } A f(){ A t(“1234"); return t; //创建返回值对象,调用拷贝构造函数用t对其初始化,随后对象t消亡 } int main(){ A a = “abcd”; a = f(); //调用重载的赋值操作符,把函数f返回的临时对象赋值给a,随后临时对象消亡 }
转移构造函数:
A(A&& x){p = x.p; x.p = NULL;}
编译程序发现t是即将消亡的对象,把它编译成调用转移构造函数。对象t消亡时不需要归还空间,等待返回值对象消亡才归还。
转移赋值函数:
A &operator=(A&& x){ if(&x==this) return *this; delete []p; p = x.p; x.p = NULL; return *this; }