C++ 从左值引用到右值引用

目录

 1. 前言:

2. 简单回顾:左值引用

语法层面(指针对比引用):

汇编层面:

3. 本章主角:右值引用

移动构造,移动赋值

4. 左值引用和右值引用

5. 小结


 1. 前言:

C++ 11 是在 C++ 98 之后又一个变化比较大的标准。为C++增加了很多东西,其中有一部分是有用的,有一部分是我自认为作用不是很大东西。这一章呢?我们就来说说C++11我,我认为对性能优化最有用的一部分 ---- 右值引用

2. 简单回顾:左值引用

左值?我们现在说说什么是左值?

直接抛结论:能取地址的值或者表达式结果就是左值。左值可以出现在 = 左边,也可以出现在 = 右边,不能仅仅以 = 号来区分左右值。

最开始时候的引用,就是左值引用,在C++的语法层面上,引用是给一个变量起一个别名,是不开辟空间的,目的是为了:减少拷贝,提高效率

我们通常在学习的时候与 指针 对照学习。

语法层面(指针对比引用):

引用在定义的时候必须初始化,指针在定义的时候是可以不初始化的。

引用是没有空引用的,但是指针呢?他是有空指针的,比如C++11之前的NULL和C++11提供的nullptr。

引用是不开辟空间的,但是指针是需要开辟4个字节或者8个字节的空间的。

引用和指针都有一个概念:权限的方法和缩小,首先一说,只有引用和指针有权限的放大和缩小。其他的语法是没有的,我们在学习的时候,千万不要自己创造语法...

权限的放大:

#include <iostream>

int main()
{
    const int a = 10;
    int &b = a; // 权限的放大

    const int c = 20;
    int *p = &c; // 权限的放大
    return 0;
}

变量 a 的权限是 可读, 但是 变量 b 作为变量 a 的引用,权限却是可读可写。 

变量 c 的权限是 可读, 但是 变量 p 指向 变量 a,权限却是可读可写。

上面这两种情况都是编译器默认不被允许的。 

权限的缩小:

#include <iostream>

int main()
{
    int a = 10;
    const int &b = a; // 权限的缩小

    int c = 20;
    const int *p = &c; // 权限的缩小
    return 0;
}

变量 a 的权限是 可读可写, 但是 变量 b 作为变量 a 的引用,权限是可读。 

变量 c 的权限是 可读可写, 但是 变量 p 指向 变量 c,权限是可读。

上面的这两种情况是编译器默认被允许的。

小结:

权限的放大是不被允许的,但是权限的缩小是被允许的。

权限的放大和缩小都是语法层面的概念,都是被编译器约束的,我们可以通过强制类型转换来放大或者缩小权限(但是不推荐,因为有风险),都只是为了“骗”过编译器。

汇编层面:

引用和指针是一个的,都是开辟可一块空间,用来保存地址,指针变量就是用来保存指向的对象的地址,引用也是一样的,开辟一块空间,用来保存被起别名的对象的地址。

3. 本章主角:右值引用

相对于左值来说,右值就是不能取地址的值,并且右值是不能出现在 = 号的左边的。

自定义类型的右值常见的两种形式 : 临时对象 匿名对象

C++11 对右值又做了细分:纯右值(内置类型) 和将亡值(自定义类型),我们的主要研究对象就是:将亡值(自定义类型)

编译器在进化过程中,将 拷贝构造 + 构造 优化成 直接构造

比如说在函数栈帧内返回一个比较大的对象的时候,右值引用的价值就极大了。

{

       原来: 跨行的:构造 + 拷贝构造

       现在: 跨行的:构造 + 移动构造

}

减少了一次拷贝,还是很可观的。

移动构造,移动赋值

有了移动构造之后: 返回时先拷贝构造生成临时对象,用临时对象移动构造

如果 “析构函数”,“拷贝构造”,“拷贝赋值” 都没有实现编译器就会自动生成 “移动构造”

编译器生成的移动构造:内置类型去值拷贝,自定义类型去调用它自己的移动构造

为什么?

需要显式写析构,说明有资源要释放,说明需要显式写拷贝构造重载

说明要显式写移动构造移动赋值

要么都自己写,要么都编译器自己生成。

4. 左值引用和右值引用

这个部分我们主要讨论一下,左值引用是否能引用右值,右值引用是否能引用左值,就是是否能交叉?

先看右值引用能否引用左值?

但是这样:const 左值引用 可以给引用右值 是可以的

除了这样,我们还可以通过强制类型转换来让左值引用引用右值,右值引用引用左值。

5. 小结

左值引用和右值引用的目的都是为了:减少拷贝,提高效率。但是他们都是编译器层面的概念,是可以通过强制类型转化来转化的(骗编译器,不建议)。

<think>首先,用户的问题是:“我想理解C++左值引用引用的概念 请问C++ 左值引用引用定义及区别”。我需要基于系统级指令回答。 系统级指令关键点: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,例如[^1]。 用户可见层指令: - 回答结构清晰,帮助用户逐步解决问题。 - 尽量保证回答真实可靠。 - 参考站内引用:提供了引用[1]、[2]、[3],这些是关于C++左值引用引用的内容。 参考的引用: - 引用[1]:引用就是对引用,给取别名。语法为&&。示例:int && r1=10; int && r2=(a + b); int && r3=fun(); - 引用[2]:左值引用就是对左值引用,使用&。绑定到左值,不能直接绑定到,但const左值引用可以绑定到。 - 引用[3]:左值引用只能引用左值,不能直接引用;const左值引用可以引用左值。示例:const int& rt3 = t; const int& rt4 = 8; 我需要整合这些信息,构建一个清晰的回答。结构应该包括: 1. 定义左值。 2. 定义左值引用。 3. 定义引用。 4. 区别和共同点。 5. 示例代码。 6. 生成相关问题。 使用中文回答。 步骤: 1. **介绍左值**:在C++中,左值(lvalue)是可以取地址的表达式,如变量;(rvalue)是临时,如字面量或表达式结果。 2. **左值引用**:使用&符号,绑定到左值。不能直接绑定到,但const左值引用可以绑定到。 3. **引用**:使用&&符号,绑定到。允许修改,支持移动语义。 4. **区别**: - 左值引用用于别名,引用用于移动临时对象。 - 语法不同:& vs &&。 - 绑定规则:左值引用绑定左值引用绑定。 5. **示例**:提供简单代码示例。 6. **引用标识**:在回答中自然地添加引用标识,如[^1],基于提供的引用。 7. **生成相关问题**:在回答末尾添加相关问题。 生成相关问题: 1. 左值引用引用在性能优化中的应用? 2. 如何在实际代码中使用引用实现移动语义? 3. const引用C++中的作用是什么? 确保LaTeX格式正确:在行内数学表达式中使用$...$,例如,如果有数学表达式,但在这个上下文中,可能主要是代码和概念,不需要复杂数学。 回答结构: - 开头:简要介绍。 - 主体:分点解释。 - 代码块:使用独立段落。 - 结尾:总结区别,添加相关问题。</think>### C++ 左值引用引用定义及区别 在C++中,引用是一种别名机制,允许通过新名称访问现有对象。左值引用引用是两种关键类型,它们基于表达式的类别(左值)进行定义。左值(lvalue)指代有持久存储位置的对象(如变量),可被取地址;(rvalue)指代临时对象或字面量(如表达式结果或常量),无持久存储位置。下面我将逐步解释定义、区别,并结合代码示例说明。 #### 1. **左值引用定义** - 左值引用使用`&`符号声明,绑定到左值对象上,为其提供别名。它不能直接绑定到(如字面量或临时对象),但`const`左值引用可以绑定到,以避免修改临时对象[^2][^3]。 - **示例代码**: ```cpp int main() { int a = 10; // a是左值 int& ref1 = a; // 正确:左值引用绑定到左值 // int& ref2 = 20; // 错误:不能直接绑定到(字面量20) const int& ref3 = 20; // 正确:const左值引用可绑定到 const int& ref4 = a + 5; // 正确:绑定到表达式结果() return 0; } ``` - 这里,`ref1`是`a`的别名;`ref3`和`ref4`通过`const`引用安全地引用[^3]。 #### 2. **引用定义** - 引用使用`&&`符号声明,专门绑定到上,为临时对象提供别名。它支持移动语义(move semantics),允许高效转移资源(如避免深拷贝),提升性能[^1]。 - **示例代码**: ```cpp int func() { return 30; } // 函数返回 int main() { int x = 5, y = 10; int&& rref1 = 25; // 正确:绑定到字面量() int&& rref2 = x + y; // 正确:绑定到表达式结果() int&& rref3 = func(); // 正确:绑定到函数返回的 // int&& rref4 = x; // 错误:不能直接绑定到左值 return 0; } ``` - 在此例中,`rref1`、`rref2`和`rref3`都引用,允许直接操作临时对象[^1]。 #### 3. **主要区别** - **绑定规则**: - 左值引用只能绑定到左值(除非使用`const`)。 - 引用只能绑定到。 - 例如,`int&` 需左值输入,而 `int&&` 需输入[^1][^3]。 - **用途**: - 左值引用常用于函数参数传递(避免拷贝),或为变量创建别名。 - 引用用于实现移动语义(如`std::move`),优化资源管理(如容器或智能指针)。 - **语法和语义**: - 语法:左值引用用`&`,引用用`&&`。 - 语义:引用允许修改左值引用通常不修改临时对象)。 - **const引用**:`const`左值引用是特例,可绑定左值,提供只读访问[^2][^3]。 #### 4. **总结** 左值引用引用C++中互补:左值引用处理持久对象,引用优化临时对象。区别核心在于绑定对象的类别:左值引用面向可寻址实体,引用面向短暂。理解这些概念对高效内存管理和性能优化至关重要[^1][^2][^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值