【C++】014、左值与右值的区别

一、左值&右值

左值:

  • 左值是有内存地址的持久对象,可以取他的地址值

右值:

  • 右值是临时的,即将销毁的对象,不能取他的地址,但可以窃取他的资源。右值的存储位置通常在栈或者寄存器内。

右值引用(T&&)

  • 右值引用是为了把右值这种临时资源拿来继续使用

二、左值与右值的鉴别方法

  • 在C++中,能对表达式使用取地址运算符&的就是左值,不能取地址的就是右值
cpp 复制代码
int a = 10;     // a 是左值(&a 合法)
int* p = &a;    // ✅ OK
// int* p2 = &10; // ❌ 编译错误!不能对字面量取地址,所以 10 是右值

三、对比

|-----------------|-----------------|---------------------|
| 对比维度 | 左值 | 右值 |
| 别名 | 有身份的 | 无身份的(临时) |
| 取地址操作(&) | 可以 | 不可以 |
| 生命周期 | 长(有自己的作用域) | 短(面临销毁) |
| 例子 | 变量(a),++i,*ptr | 字面量10,i++,MyClass() |
| 能否放在=左边 | 通常可以 | 不可以(除非使用move) |
| 右值引用(T&&) | 不可以(除非使用move) | 可以 |

四、移动赋值操作:std::move

1、窃取资源

  • std::move 本质上只是一个强制类型转换(static_cast),不移动任何东西,只是将左值变成右值。

  • 真正的移动发生在移动构造函数和移动赋值运算赋里,编译器看到右值,从而窃取资源而非深拷贝

  • 代码

cpp 复制代码
#include <iostream>
#include <vector>
#include <utility> // for std::move

class BigData {
private:
    std::vector<int> data; // 假设很大,10000个元素
public:
    // 1. 构造函数(建立资源)
    explicit BigData(size_t size) : data(size, 1) {
        std::cout << "Constructed (allocated memory)\n";
    }

    // 2. 拷贝构造函数(深拷贝,开销大)
    BigData(const BigData& other) : data(other.data) {
        std::cout << "Copied (expensive deep copy)!\n";
    }

    // 3. 移动构造函数(轻量级指针交换,C++11核心!)
    BigData(BigData&& other) noexcept : data(std::move(other.data)) {
        // 精髓:直接窃取 other 的内部指针,other.data 变为空
        std::cout << "Moved (cheap pointer swap)!\n";
    }
};

BigData createBigData() {
    BigData temp(10000); // 创建临时对象(左值)
    return temp;         // 返回时触发移动语义(C++17强制拷贝省略前,优先选移动)
}

int main() {
    BigData obj1(10000);           // 构造
    BigData obj2 = obj1;           // 拷贝(深复制,慢) -> 输出 "Copied!"
    BigData obj3 = std::move(obj1); // 移动(偷数据,快) -> 输出 "Moved!"
    // 注意:此时 obj1 处于"有效但未指定"的状态(通常是空),不要再使用 obj1!
}

2、右值引用(T&&)专门用来捕获右值,从而在不拷贝的情况下转移资源

  • 右值引用智能绑定右值,如果想把左值当右值用,必须通过move显示转换
cpp 复制代码
int a = 5;
int& lr = a;               // OK
// int& lr2 = 10;          // ❌ 错误
const int& clr = 10;       // ✅ OK(临时对象生命周期被延长到引用生命周期)
int&& rr = 10;             // ✅ OK
// int&& rr2 = a;          // ❌ 错误(不能直接绑左值)
int&& rr3 = std::move(a);  // ✅ OK(强制转换,此时a的资源可以被偷)

3、总结:

  • 左值是有户口本的居民; 右值是有暂住证的旅客; move是让居民办理临时注销,把资源合法转移给新用户。
相关推荐
曦樂~6 小时前
Cpp面筋
c语言·c++
道尔柯南6 小时前
C++ string 类详解:从常用接口到深拷贝,彻底掌握字符串处理
android·java·c++
来让爷抱一个7 小时前
Python 异步里混用同步库,事件循环被卡住的全过程
开发语言·python
十二9 小时前
【洛谷题解】P1083 [NOIP 2012 提高组] 借教室(二分答案 + 差分)
数据结构·c++·算法·蓝桥杯
心祭丫丫10 小时前
【每天一个 Python 小案例17】Python 实现通讯录
开发语言·人工智能·笔记·python·学习
露天赏雪10 小时前
第3篇:Sentinel熔断降级实战:大模型接口抖动时的服务兜底方案
java·开发语言·人工智能·spring boot·spring·servlet·sentinel
D e re k ZH11 小时前
C++ 从零入门(一):基础语法与程序结构
数据结构·c++·算法
yeccheng12 小时前
MySQL 索引超详解:从底层 B+ 树到面试高频考点
java·开发语言·jvm·mysql·面试
联犀12 小时前
纯 Go 的 CAD 开源库 go-cad:直接解析 DWG/DXF,现在也能导出 PDF
开发语言·golang·pdf
zjxtxdy13 小时前
C++面向对象程序开发-类与对象
开发语言·c++