目录
1、什么是左值?
左值是一个表示数据的表达式(如变量名、解引用以后的指针)。左值可以取地址和赋值,因为变量一旦被声明,就会在栈上或者堆上开辟一块相应的空间。我们可以取地址来访问到这块空间。
左值引用就是给左值起别名,语法格式:数据类型& 别名 = 初始值
应用场景:
- 作为函数参数,可以减少拷贝:void func(int& x)
- 作为函数返回值,可以返回引用:int& func()
- 存在缺陷,无法返回临时变量
- 因为出了作用域,临时变量就被销毁了,一个被销毁的临时变量的引用是无效的
- 右值引用解决 “ 函数返回临时变量或者对象 ” 的问题
int main()
{
// p、b、c都是左值
int* p = new int(0);
int b = 1;
const int c = 2;
// rp、rb、rc是上述左值的引用
int*& rp = p;
int& rb = b;
const int& rc = c;
return 0;
}
2、什么是右值?
右值也是一个表示数据的表达式,如字面常量、表达式返回值、函数返回值等。右值不能取地址,因为一般右值都是一些临时变量,比如函数返回值,函数执行完毕以后,会将返回值赋值给寄存器或者一个临时变量,我们无法获取一个临时变量的地址。
右值引用就是给右值起别名,语法格式:数据类型&& 别名 = 初始值
应用场景:
- 移动构造(解决上述返回临时变量或者对象的问题)
- 移动赋值
int main() {
double x = 1.1, y = 2.2;
// 以下是常见的右值
10 // 常量
x + y // 表达式的返回值
func(x, y) // 函数返回值
// 以下依次给上述右值起别名
int&& rr1 = 10;
double&& rr2 = x + y;
double&& r33 = func(x, y);
return 0;
}
注意:const修饰的变量虽然也是常量,但被归为左值。因为在声明的时候,编译器会为其分配一块空间来保存const修饰的常量。
3、左值和右值的区分
不能简单的通过是否为常量 或者 是否可以取地址来区分左值和右值,要根据表达式结果或变量的性质判断。
左值:
- 普通类型的变量,可以取地址
- const修饰的常量(原本也是变量,只不过权限变为只读)
- 引用
右值:
- 运行结果是一个临时变量或者对象
4、左值和右值的交叉引用
左值引用可以引用左值,右值引用可以引用右值,这个在上面介绍左值和右值的案例中已经体现了,现在问题来了,左值和右值能否交叉引用?
(1) 左值引用能否引用右值?
举例: int& num = 10;
成立与否:不成立
解决方法:添加const关键字修饰
const int& num = 10;
(2) 右值引用能否引用左值?
举例:int&& rr = a; // a 是一个变量
成立与否:不成立
解决方法:使用move函数将左值转换成右值
int a = 10;
int&& rr = move(a); //