在C++中,左值(lvalue)是可以获取其地址的一个量。由于经常出现在赋值语句的左边,因此称之为左值。例如一个有名称的变量。 例如:
int a=10;
//a就是一个左值。
传统的C++引用,都是左值引用。例如:int &ra=a;将ra关联到a。这就是左值引用。
C++11,新增了右值引用的概念。用&&代表右值引用。
首先我们来看一下什么叫做右值。可以说所有不是左值的量都是右值。例如文本,临时对象或者临时值(都是不能获取地址的量)。
右值引用,就是一个对右值的引用。特别地,这是一个当右值是一个临时对象时使用的概念。例如。
int &&ra=10;
10就是一个右值,ra将是10这个右值的引用。看例子:
#include <iostream> using namespace std; int main() { int &&ra=9; cout<<&ra<<endl<<ra<<endl; ra=5; cout<<&ra<<endl<<ra<<endl; cin.get(); }
输出结果:
有趣的是,将右值关联到右值引用将导致该右值被存储到特定的位置,且可以获取该位置的地址。例如,你不能对右值9或者5进行&运算,但是可以对ra进行&运算。
右值引用的目的是提供一些涉及临时对象时可以选用特定的方法(主要是复制构造函数以及operator=,但并不限于此)。由于知道临时对象会被销毁,通过右值引用,某些涉及复制大量数据的操作可以通过简单地复制指向这些值的指针来实现。
方法可以将&&作为参数说明的一部分,从而指定右值引用参数。看例子:
#include <iostream> using namespace std; void showMax(int &a,int &b){ if(a>b) cout<<a<<endl; else cout<<b<<endl; } int main() { int a=10; int b=5; showMax(a,b); //showMax(20,15); // invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'| cin.get(); return 0; }
发现showMax(20,15)的时候无法正常编译。
这是因为20,15是一个右值。下面我们定义一个右值引用版本的showMax();
#include <iostream> using namespace std; void showMax(int &a,int &b){ if(a>b) cout<<a<<endl; else cout<<b<<endl; }; void showMax(int &&a,int &&b){ cout<<"这是一个右值引用比较"<<endl; if(a>b) cout<<a<<endl; else cout<<b<<endl; } int main() { int a=10; int b=5; showMax(a,b); showMax(20,15); return 0; }
运行结果:
当调用showMax(20,15)的时候,编译器将自动调用相对应的右值引用的版本。
作为方法的参数的时候右值引用非常有用,又例如:
#include <iostream> using namespace std; void show(int &a){ cout<<"左值引用:"<<a<<endl; }; void show(int &&a){ cout<<"这是一个右值引用:"<<a<<endl; } int main() { int a=10; int b=5; show(a); show(a+b); show(a++); //右值引用 show(++a); //左值引用 show(b+100); show(100+200); }
结果:
需要注意的是:
show(a++); //右值引用
show(++a); //左值引用
a++是先取出持久对象a的一份拷贝,再使持久对象a的值加1,最后返回那份拷贝,而那份拷贝是临时对象(不可以对其取地址),故其是右值;
++a则是使持久对象a的值加1,并返回那个持久对象a本身(可以对其取地址),故其是左值。
右值引用单独使用的情况很少,一般都是用于作为方法的参数或者函数的参数,使用的最多的情况则是用在移动语义之上。