1、左值与右值
左值和右值是表达式的属性,核心区别在于:能否取地址、是否有持久的存储。
1.1 左值:有名字、能取地址、可被修改(通常)
左值是 “可以放在赋值号左边” 的表达式(但并非绝对,如 const 左值不能被修改),它有明确的内存地址,生命周期较长(如变量)。- int a = 10; // a 是左值(有名字、能取地址)
- int* p = &a; // 合法:左值可以取地址
- const int b = 20; // b 是 const 左值(有名字、能取地址,但不能修改)
- // b = 30; // 错误:const 左值不可修改
- int arr[5];
- arr[0] = 1; // arr[0] 是左值(数组元素有地址)
复制代码 1.2 右值:无名字、不能取地址、临时存在
右值是 “只能放在赋值号右边” 的表达式,通常是临时结果(如字面量、表达式计算结果),没有持久的内存地址,生命周期短暂(表达式结束后销毁)。- int a = 10;
- int b = 20;
- // 以下都是右值
- 100; // 字面量(无名字,不能取地址)
- a + b; // 表达式结果(临时值,无名字)
- func(); // 函数返回值(非引用类型时,是临时值)
复制代码 关键特征:
- 右值不能被取地址:&(a + b) 会编译报错(无法对临时值取地址)。
- 右值是 “消耗品”:使用后就会销毁(除非被保存到左值中)。
右值的细分
C++11 后,右值又分为两种,但日常使用中无需严格区分,知道它们都是右值即可:
- 纯右值(Prvalue):字面量(如 10)、表达式结果(如 a + b)、非引用返回的函数结果。
- 将亡值(Xvalue):通过 std::move 转换后的左值(本质是 “即将被销毁的左值”,可被移动)。
2、左值引用:绑定左值的 “别名”
左值引用是最常用的引用类型,用 & 表示,只能绑定左值,本质是给左值起一个 “别名”,操作引用等价于操作原对象。
2.1 基本用法
- int a = 10;
- int& ref_a = a; // 正确:左值引用绑定左值(ref_a 是 a 的别名)
- ref_a = 20; // 等价于 a = 20,a 现在是 20
复制代码 2.2 左值引用的限制
- 不能绑定右值
- // int& ref = 10; // 错误:左值引用不能绑定右值(10 是右值)
复制代码 - const 左值引用是特例:可以绑定右值(临时延长右值的生命周期):
- const int& ref = 10; // 正确:const 左值引用可绑定右值
- // 原理:编译器会生成临时变量存储 10,ref 绑定这个临时变量(临时变量生命周期被延长至 ref 相同)
复制代码 2.3 左值引用的用途
- 避免函数传参时的拷贝(如传递大对象 vector):
- void func(const vector<int>& v) { ... } // 传引用,无拷贝
复制代码 - 允许函数修改外部变量(非 const 引用):
- void increment(int& x) { x++; }
- int a = 5;
- increment(a); // a 变为 6
复制代码 3、右值引用:绑定右值的 “专属引用”
右值引用是 C++11 新增的引用类型,用 && 表示,专门绑定右值,目的是 “利用右值的临时特性” 实现移动语义(避免不必要的拷贝)。
3.1 基本用法
- int&& ref1 = 10; // 正确:右值引用绑定纯右值(10 是右值)
- int a = 10, b = 20;
- int&& ref2 = a + b; // 正确:右值引用绑定表达式结果(右值)
复制代码 3.2 右值引用的限制
- 不能直接绑定左值:
- int a = 10;
- // int&& ref = a; // 错误:右值引用不能直接绑定左值
复制代码 - 但可以通过 std::move 将左值 “强制转换” 为右值引用(本质是告诉编译器:“这个左值可以被当作右值处理,资源可以被转移”)
- int a = 10;
- int&& ref = std::move(a); // 正确:std::move 将 a 转为右值引用
复制代码 注意:std::move 不会移动任何数据,只是 “标记” 左值为 “可被移动” 的右值,本身是编译期操作,无运行时开销。
3.3 右值引用的核心用途:移动语义
右值引用的最大价值是实现移动语义—— 对于临时对象(右值),不再进行昂贵的拷贝,而是直接 “窃取” 其资源(如内存),大幅提升性能。
移动构造函数
[code]class MyString {private: char* data; // 存储字符串的动态内存public: // 普通构造函数 MyString(const char* str) { size_t len = strlen(str); data = new char[len + 1]; strcpy(data, str); cout |