- 引用是一个变量,它引用其他变量的内存位置
int x = 34;
int &lRef = x;
- 标识符 IRef 就是一个引用。在声明中,引用是通过 & 来指示的,出现在类型与变量的标识符之间,这种类型的引用称为左值引用
- 左值看作是一个关联了名称的内存位置,允许程序的其他部分来访问它, "名称" 解释为任何可用于访问内存位置的表达式
- 右值则是一个临时值,它不能被程序的其他部分访问
int square(int a)
{return a * a;
}
int main()
{int x = 0; // 1x = 12; // 2cout << x << endl; // 3x = square(5); // 4cout << x << endl; // 5return 0;
}
- x 是一个左值,这是因为 x 代表一个内存位置,它可以被程序的其他部分访问,例如上面注释的第 2、3、4 和 5 行
- 表达式 square(5) 却是一个右值,因为它代表了一个由编译器创建的临时内存位置,以保存由函数返回的值。该内存位置仅被访问一次,也就是在第 4 行赋值语句的右侧。在此之后,它就会立即被删除,再也不能被访问了。对于包含右值的内存位置来说,其本质就是:它虽然没有名称,但是可以从程序的其他部分访问到它
- C++11 引入了右值引用的概念,以表示一个本应没有名称的临时对象。右值引用的声明与左值引用类似,但是它使用的是 2 个
&
符号(&&)
int && rRef = square(5);
cout << rRef << endl;
- 声明一个右值引用,给一个临时内存位置分配一个名称,这使得程序的其他部分访问该内存位置成为了可能,并且可以将这个临时位置变成一个左值。
- 右值引用不能约束到左值上,所以,以下代码将无法编译:
int x = 0;
int && rRefX = x;
- 初始化完成之后,这个包含值 square(5) 的内存位置有了一个名称,即 rRef1,所以 rRef1 本身变成了一个左值。这意味着后面的这个初始化语句将不会编译:int && rRef2 = rRef1;究其原因,就是右侧的 rRef1 不再是一个右值。综上所述,临时对象最多可以有一个左值引用指向它。如果函数有一个临时对象的左值引用,则可以确认,程序的其他部分都不能访问相同的对象
int && rRef1 = square(5);
- 右值一般是不可寻址的常量,或在表达式求值过程中创建的无名临时对象,短暂性的。
- 左值是可寻址的变量,有持久性;
- 左值和右值主要的区别之一是左值可以被修改,而右值不能。
- 左值引用:引用一个对象;
- 右值引用:就是必须绑定到右值的引用,C++11中右值引用可以实现“移动语义”,通过 && 获得右值引用。
-
右值引用和相关的移动语义是C++11标准中引入的最强大的特性之一,通过std::move()可以避免无谓的复制,提高程序性能。
特殊情况
- 但const左值引用除外,由于const的不可变性,所以const引用可以指向右值,我们经常使用const引用作为函数参数传递 const int &e = a*3; // 正确:左值引用,const引用可以绑定到一个右值上
例子
int x = 6; // x是左值,6是右值
int &y = x; // 左值引用,y引用xint &z1 = x * 6; // 错误,x*6是一个右值
const int &z2 = x * 6; // 正确,可以将一个const引用绑定到一个右值int &&z3 = x * 6; // 正确,右值引用
int &&z4 = x; // 错误,x是一个左值
参考链接
- C++左值和右值(详解版)
- 一篇文章弄懂C++左值引用和右值引用 - html中文网