C++ 左值与右值 左值引用与右值引用
C++ 左值与右值 左值引用与右值引用
左值与右值
1
2
3
int a = 10; // a是左值, 10是右值
int *p = &a; // *p是左值, &a是右值
*p = 20;
左值: 表示某个特定内存位置的表达式
- 可以被赋值(可以出现在赋值号的左边和右边)
- 有明确的内存地址
- 例如:
int a = 10;
中的a是左值
右值: 不能被赋值的表达式
- 不能出现在赋值号的左边
- 临时变量
- 例如:
int a = 10;
中的10是右值
++i: i是左值, 返回的是自增之后的变量本身, 可以被赋值 i++: i是右值, 返回的是自增之前的变量, 不能被赋值
左值引用与右值引用
1
2
int a = 10;
int& b = a;
左值引用: int& b = a;
- b是左值引用, a是左值
- 这里引用的
a
需要在之前已经定义过, 且a
是左值, 即之前有:int a = 10;
1
int&& c = 10;
右值引用: int&& a = 10;
- 这里引用的
10
是右值, 可以是临时变量 - 取右值引用时, 会先用一个临时变量保存右值, 然后将这个临时变量的地址赋给右值引用
右值本来是没有地址的, 但是编译器会通过临时变量保存右值, 可以取到这个临时变量的地址, 然后将这个地址赋给右值引用
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
int Handle(int& l) {} // 接受左值引用
int Handle2(int&& r) {} // 接受右值引用
int main(){
int a = 10;
Handle(a); // 调用Handle函数, 传入的是左值
Handle(10); // 编译错误, 传入的是右值, 但是Handle函数需要的是左值
Handle2(10); // 调用Handle2函数, 传入的是右值
Handle2(a); // 编译错误, 传入的是左值, 但是Handle2函数需要的是右值
}
左值引用与右值引用的意义
右值有一个特殊的性质, 就是基本上只会被使用一次, 对于这种只会被使用一次的右值, 如果是比较大的数据(例如一个很大的数组), 如果用左值引用, 那么会拷贝一份数据, 但是如果用右值引用, 那么只会拷贝一个地址, 节省了内存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <vector>
// 函数重载分别接受左值引用和右值引用
void Process(const std::vector<int>& v) {
std::cout << "Left value reference\n";
}
void Process(std::vector<int>&& v) {
std::cout << "Right value reference\n";
// 在这里可以直接操作 v 的资源,而不拷贝
}
int main() {
std::vector<int> v = {1, 2, 3};
Process(v); // 调用左值版本
Process(std::move(v)); // 调用右值版本
}
使用 std::move 将 v 转化为右值, 从而调用右值引用版本的函数, 这样就可以直接操作 v 的资源, 而不拷贝
本文由作者按照 CC BY 4.0 进行授权