
左值与右值
C++中左值与右值的概念是从C中继承而来,一种简单的定义是左值能够出现再表达式的左边或者右边,而右值只能出现在表达式的右边。
int a = 5; // a是左值,5是右值
int b = a; // b是左值,a也是左值
int c = a + b; // c是左值,a + b是右值
另一种区分左值和右值的方法是:有名字、能取地址的值是左值,没有名字、不能取地址的值是右值。比如上述语句中a,b, c是变量可以取地址,所以是左值,而5和a + b无法进行取地址操作,因此是右值。C++中左值与右值的一个主要的区别是:左值可以被修改,而右值不可修改。
左值引用与右值引用
了解了左值与右值的概念后,接下来介绍下C++中的左值引用与右值引用。左值引用很简单,就是一个变量的别名,绑定到一个左值上:
int a = 1;
int& b = a; //a = 1,b = 1
b = 2; // a = 2,b = 2
这里b就等于a,在汇编层面其实和普通的指针一样,对引用的修改(b)也会修改到被引用的对象(a),需要注意的是,因为引用实际是一个别名,因此必须初始化,即告诉编译器是那个具体对象的别名。因此下列左值引用都是错误的:
int& a; // 错误!左值引用必须初始化
int& b = 10; // 错误!左值引用不能以临时变量初始化(临时变量没有地址)
右值引用是C++11中新增的特性,顾名思义,右值引用就是用来绑定到右值的引用,一个右值被绑定到右值引用之后,原本需要被销毁的此右值生命周期会延长至绑定它的右值引用的生命周期。在汇编层面,右值引用和const引用所做的事情是一样的,即产生临时量来存储常量。但是右值引用可以进行读写操作,而const引用只能进行读操作。绑定右值引用使用&&,具体使用如下:
int a = 5;
int& b = a; // 正确!b是一个左值引用
int&& c = 6; // 正确!c是一个右值引用,绑定到右值6
int&& d = a * 2; // 正确!d是一个右值引用,绑定到右值a * 2
int&& e = i; // 错误!不能将左值绑定到右值引用
int& f = 7; // 错误!不能将右值绑定到左值引用
const int& g = a * 3; // 正确!可以将右值绑定到const 左值引用
可以看到我们虽然不能将右值绑定到左值引用,但是可以将右值绑定到const左值引用。
注意: 变量表达式都是左值!。变量可以看作是只有一个运算对象而没有运算符的表达式,跟其他表达式一样,变量表达式也有左值/右值属性。变量表达式都是左值,因此我们不能将一个右值引用绑定到一个右值引用类型的变量上。
int&& a = 5; // 正确!a是一个右值引用
int&& b = a; // 错误!a是一个左值,不能绑定到右值引用
这里虽然a是右值引用类型,但是确实一个左值,因此无法绑定到右值引用b上。因为在C++中,右值一般是临时对象,但是绑定到右值引用之后,其生命周期变长了,因此a是一个左值。我们不能将一个右值引用直接绑定到一个变量上,即使是这个变量是右值引用类型也不行。具体的这个问题在后续的介绍forward

本文深入探讨了C++中的左值与右值的概念,包括它们的定义和区别,以及如何通过左值引用和右值引用进行更灵活的编程。还介绍了左值/右值引用的模板实参推断,以及std::move和std::forward这两个关键函数的工作原理和应用场景,帮助理解C++11及以后版本中右值引用的重要性和用法。

1129

被折叠的 条评论
为什么被折叠?



