C++ 左值、右值与 std::move
2025-03-30
“左值”与“左值引用”
下面代码中,a
属于自己的内存空间,它是左值。而
10
和 20
没有地址属性,只是一个常量,都不能放在常量左边,它们都是右值。
1 | int a = 10; // a 就是地址别名 |
下面的 b
就是左值引用。引用是变量的别名,引用通过指针来实现。
1 | int a = 10; |
此时我们将 b
修改,类似于指针会帮我们做一次
*
解引用,直接修改了 a
。
1 | b = 20; |
“右值”与“右值引用”
右值一般没有地址。我们可以这么理解,右值引用就是右值的临时变量。
1 | const int&& c = 20; |
move 移动语意
std::move
的作用是将左值转换为右值。
上面的代码中,10
、20
都是纯右值,在汇编里是没有任何地址属性。我们来看看,如何使用
std::move
将左值转换为右值,在汇编中是怎么样的。
1 | const int&& c = std::move(a); |
我们发现,这和左值引用一模一样!左值引用是:
1 | int& b = a; |
更准确来说 std::move
仅仅是将包裹着 move
的
a
变成了右值,而变量 c
依旧是指向
a
的引用。其中 a
叫做将亡值。唯一的目的:让 c
在传递或者赋值时,触发移动构造,避免深拷贝。下面是一个例子:
1 | std::string str1 = "Helloooooooooooooooooooooooo"; |
不过要注意,std::move
之后,在语意上我们将原来的左值给“移动”了,再去访问原来的对象就不符合移动语意。下面的例子中进行了一次非法访问,如果是更复杂的变量,可能会出现
core dump 的情况。
1 | std::cout << "str1: " << str1 << std::endl; |