什么是左值和右值
(1) 左值(LValue)
- 具有地址, 存储在内存中
- 可以出现在赋值号 = 的左侧
- 可以取地址 &
- 变量、对象、数组元素都是左值
示例:
int x = 10; // x是左值
x = 20; // 左值可以出现在赋值号的左侧
int* p = &x; // 可以取地址
(2) 右值(RValue)
- 通常没有地址, 存储在寄存器或者临时内存中
- 不能出现在赋值号 = 的左侧
- 不能取地址 & (除非绑定到const左值引用)
- 字面量、表达式计算结果都是右值
const int&& c = 10; // 右值的临时变量
// lea rax, [a]
// mov qword ptr[c], rax
const int&& c = std::move(a); // std::move(a)变为一个右值(又称亡值), 然后右值引用
std::move
(1) 作用
- 将左值转换成右值,以触发移动语义
- 不会真正"移动"数据,只是改变对象的属性
- 用于触发移动构造和移动函数,避免深拷贝,提高性能
int main() {
std::string str1 = "Hello";
std::string str2 = str1; // 触发移动构造(深拷贝)
std::string str2 = std::move(str1); // str1 可能为空
}
(2) 底层原理
std::move() 只是 static_cast<T&&>, 不会改变对象的生命周期
template <typename T>
constexpr remove_reference_t<T>&& move(T&& t) noexcept (
return static_cast<remove_reference_t<T>&&>(t);
}
- std::move(a)只是告诉编译器a变成右值, 但不会修改a本身
- rref绑定a的地址, 可以继续使用a, 但内容可能已经变空(只有类类型,如 std::string 才有移动语义和资源搬迁,才会清空原变量内容)
示例:
int a = 10;
int&& rref = std::move(a);