C++ 左值与右值

52 阅读1分钟

什么是左值和右值

(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);