右值和右值引用【C++】

文章目录

  • 左值引用和右值引用简单介绍
    • 左值:
    • 右值:
    • 左值引用,引用右值
    • 右值引用,引用左值
    • 为什么强制类型转换之后,右值引用就可以引用左值了呢?
  • 右值引用的作用
    • 举个例子理解移动构造和移动赋值的作用:
      • 移动构造
      • 移动赋值:
  • 右值引用的属性
  • 万能引用
  • 完美转发

左值引用和右值引用简单介绍

左值:

左值是一个表示数据的表达式
它最主要的特点就是:
可以取地址
生命周期比较长,最短都是局部变量的生命周期
可以出现在=左边,即可以被修改

然后把地址给引用或者指针,就可以通过引用或者指针改变这个左值

左值引用就是给左值取别名
左值可以出现在=的左右两边


右值:

右值也是一个表示数据的表达式
[右值一般都是临时性的东西,是用临时的空间存储的临时变量,匿名对象等]

在这里插入图片描述

右值最主要的特点就是:
不能取地址
生命周期很短,一般就一行
不可以出现在=左边,即不能被修改

右值引用就是给右值取别名
右值只能出现在=的右边


左值引用,引用右值

在这里插入图片描述

右值引用,引用左值

在这里插入图片描述
move本质就是强制类型转换
[move不会改变它的()里面的参数的类型,只是它的返回值是右值类型的而已]


为什么强制类型转换之后,右值引用就可以引用左值了呢?

这是因为底层[汇编层次]里面是没有左值和右值的区别的
底层里面甚至都没有变量名这些用合法标识符定义名称这个概念,变量名都是给人看的,机器不用看也看不懂
只有地址和这个地址对应的空间,只需要从这些空间里面取值
右值只是在语法层面上不可以取地址
因为右值也开了空间,开了空间这个空间就有自己对应的地址
底层实现的时候是肯定可以取地址的,不然就拿不到里面的值了

左值引用和右值引用,底层实现的时候是没有区别的
都是开一个4(8)字节大小空间存储引用的变量的地址
在使用引用的语法的时候,编译器自动帮我们解引用

所以我们只要在语法层面通过了编译器的检查
右值引用指能引用右值,那就把左值的类型强制类型转换成右值类型

通过了之后左值引用和右值引用底层实现因为是一样的,所以就没有问题了


右值引用的作用

就是减少深拷贝
一般体现在在移动构造和是移动赋值上
即:
调用移动构造/移动赋值时
如果是内置类型最简单的就是浅拷贝了,没法再优化了
②如果是自定义类型,那就再调用它的移动构造呗
如果是申请的资源(堆区资源等)此时就直接交换它们指向资源的指针就可以了
所以移动构造/移动赋值可以减少深拷贝


举个例子理解移动构造和移动赋值的作用:

如果一个函数的返回值是string的对象,而且是传值返回,函数外面有一个对象接收这个函数的返回值

此时
语法上:
①函数结束之前,先用要返回的string对象拷贝构造出一个临时对象
②函数调用结束之后,再用临时对象拷贝构造出函数外接收它的目标对象

编译器优化之后
函数调用结束之前,直接使用要返回的对象拷贝构造出接收它的目标对象
在这里插入图片描述

所以即使编译器再怎么优化,也最少还需要一次深拷贝,才能完成返回并接收返回值

此时就可以使用
用右值引用写出来的移动构造


移动构造

一般都移动构造就是:
就是用swap去抢临时对象(右值)的资源

为什么可以直接swap抢夺返回值的资源呢?
因为返回对象的时候构造的对象是右值,是临时对象,只要出了函数的作用域就一定会销毁

既然他一定会销毁
那为什么还要花时间拷贝他的资源,直接用swap抢过来(交换资源指针的指向)就可以了

即:
有了移动构造之后:
在这里插入图片描述


移动赋值:

移动赋值的实现:也是用swap去抢临时对象(右值)的资源
在这里插入图片描述

为什么不是浅拷贝右值,必须swap?
因为:
如果浅拷贝的话,右值里的成员指针还指向他的资源,右值析构的时候就会把资源释放掉
这个时候不仅没有抢夺资源成功,还会野指针
只有swap了,右值里面的成员指针,就指向了我不要的资源,或者指了空


所以
①如果外面接收返回值的对象是已经创建了的对象,这个时候就调用移动赋值

②如果是创建一个对象去接收传值返回的返回值,就调用移动构造

所以有了移动构造和移动赋值之后
就可以放心大胆地使用传值返回了, 因为swap的代价非常低,是O(1)

右值引用的作用还体现在插入push,insert等传进去的参数会在函数体中被深拷贝或者传值传参等
只要有深拷贝的地方就有用


在这里插入图片描述

上图的push_back也能根据传入的是左值还是右值,调用不同的重载

插入s1的时候为什么会深拷贝?
因为插入的底层实现,是把对象的拷贝插进去,不是把对象本体插进去

但是如果是临时对象的话,因为他的生命周期只有一行(句),所以直接把他的资源抢走也没问题


右值引用的属性

右值就是右值
但是右值引用是左值
为什么右值引用是左值?
右值不仅不可以取地址,它还有一个特性是不能被修改[即前面提到的临时变量具有常属性]
因为
①右值引用可以出现在=的左边
所以右值引用要是可以修改的
而且swap使用的是就是右值引用,如果右值引用不能修改,那就没有办法修改右值中资源指针的指向,就没办法抢夺右值的资源了
在这里插入图片描述
注意:
swap没有右值引用的版本,因为不需要,写了反而可能误操作
一般情况下是不会把右值传给swap的,因为右值的设定就是不能修改
移动构造/移动赋值也是把右值引用传给swap,右值引用也是左值
右值引用是左值,所以移动构造/移动赋值时调用swap的时候,传给swap的就是左值

②右值引用生命周期比较长
③右值引用可以取地址


所以
右值引用作为函数参数传递的时候,它是作为左值传递过去的,编译器匹配也是匹配左值对应的函数


如果调用的是

list<string> a;
a.push_back("xxxxx";

这个时候他调用的确实是下图第2个参数是右值引用的push_back,因为他传入的"xxxx"会被编译器自动优化为右值
在这里插入图片描述

但再下一层就不一样了
因为接收右值的x是右值引用
所以x是左值
所以push back里面传给insert的x是左值
在这里插入图片描述

所以他这个时候匹配的insert是上图第一个,左值引用对应的重载

所以如果要让push_back里面调用到的insert匹配到的是右值引用的重载,传参的时候就得把右值引用先变成右值
就得用一下的两种方法中的一个
①move一下,即push_back(move(x))

②完美转发一下,即push_back(forward(x))


万能引用

语法:

template<class  T1,class T2,……>
返回值  函数名(T1&&,T2&&,……)
{
函数体
}


在这里插入图片描述

注意:
函数模板里面的&&,不是表示右值引用,而是万能引用
即如果传进来的参数的类型是
①左值,就T&&就实例化成对应的左值引用

②右值,就T&&就实例化成对应的右值引用

但其实这个时候还有一个问题:
如果这个函数模板还要调用其他的函数(函数模板)的时候,传参怎么传?

就像上图中的
如果函数模板还要调用fun
这个时候我们期望函数模板要做到的是
①如果传进来的是左值,那么传给fun的也应该是左值

②如果传进来的是右值,那么传给fun就应该是右值

此时就有一个问题
右值传给函数模板之后,右值引用接收了右值
但右值引用本身是左值
此时如果直接把右值引用传给fun,就相当于是传给了它左值,这于我们的期望不符

这个时候就要使用完美转发了

在这里插入图片描述


完美转发

forward()
forward是一个函数模板

作用:
传给他一个右值引用,forward就返回右值引用,引用的右值

传给他一个左值引用,forward就返回左值引用,引用的左值


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/43190.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

罗杰斯特回归

定义 逻辑回归其实就是原来的线性回归加了激活函数&#xff0c;这个函数其实就是sigmoid函数&#xff0c;把一个回归的连续数值压缩到了0到1的空间&#xff0c;其实只要有函数能够满足把数值压缩到0,1之间就可以&#xff08;因为0到1之间的数值就是概率值&#xff09; 对于分类…

Elasticsearch 高级

Elasticsearch 高级 建议阅读顺序&#xff1a; Elasticsearch 入门Elasticsearch 搜索Elasticsearch 搜索高级Elasticsearch高级&#xff08;本文&#xff09; 1. nested 类型 1.1 介绍 Elasticsearch 中的 nested 类型允许你在文档内存储复杂的数据结构&#xff0c;比如一个…

基于SpringBoot实现的高校实验室管理平台功能四

一、前言介绍&#xff1a; 1.1 项目摘要 随着信息技术的飞速发展&#xff0c;高校实验室的管理逐渐趋向于信息化、智能化。传统的实验室管理方式存在效率低下、资源浪费等问题&#xff0c;因此&#xff0c;利用现代技术手段对实验室进行高效管理显得尤为重要。 高校实验室作为…

leetcode_704. 二分查找_java

704. 二分查找https://leetcode.cn/problems/binary-search/ 1.题目 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 示…

python基础学习三(元组及字符串的使用)

文章目录 元组什么是元组元组的创建方式为什么要将元组设计成不可变序列元组的遍历集合集合的相关操作集合操作集合的数学操作集合生成式列表&#xff0c;字典&#xff0c;元组&#xff0c;集合总结 字符串字符串的驻留机制判断字符串的操作方法字符串的比较操作字符串的切片操…

游戏被外挂攻破?金融数据遭篡改?AI反作弊系统实战方案(代码+详细步骤)

一、背景与需求分析 随着游戏行业与金融领域的数字化进程加速,作弊行为(如游戏外挂、金融数据篡改)日益复杂化。传统基于规则的防御手段已难以应对新型攻击,而AI技术通过动态行为分析、异常检测等能力,为安全领域提供了革命性解决方案。本文以游戏反作弊系统和金融数据安…

深入理解 TypeScript 中的类型断言(Type Assertion)

类型断言是 TypeScript 中一个强大而独特的特性&#xff0c;它允许开发者告诉编译器&#xff1a;"我知道这个值的类型是什么&#xff0c;请相信我"。本文将全面探讨类型断言的概念、语法、使用场景、最佳实践以及潜在陷阱&#xff0c;帮助你在 TypeScript 开发中更有…

matplotlib标题比x,y轴字体大,明明标题字体更大?

原始代码&#xff1a; plt.xlabel(训练轮次&#xff08;Epochs&#xff09;, fontsize14, fontweightbold, fontpropertieschinese_font) # 设置中文字体、加大、加粗 plt.ylabel(R值, fontsize14, fontweightbold, fontpropertieschinese_font) # 设置中文字体、加大、加粗…

MySQL DQL,数据查询语言的用法

语法&#xff1a;select 字段名 from 表名 [where <条件>]选择符合条件的记录 group by 字段名表 :分组 having <条件> :选择符合条件的组 order by 字段名表 …

Python练习之抽奖界面

前言 一、代码整体架构分析 1、数据层 (Model) 2、控制层 (Controller) 3、视图层 (View) 二、核心功能实现详解 1、 文件导入功能 1.1、实现逻辑 1.2、代码涉及知识点讲解 1.2.1、wildcard 1.2.2、wx.FileDialog 1.2.3、dlg.ShowModal() 2、抽奖动画控制 1.1、…

Vue3 项目通过 docxtemplater 插件动态渲染 .docx 文档(带图片)预览,并导出

Vue3 项目通过 docxtemplater 插件动态渲染 .docx 文档&#xff08;带图片&#xff09;预览&#xff0c;并导出 预览安装插件示例代码项目目录结构截图实际效果截图 动态渲染 .docx 文档&#xff08;带图片&#xff09;&#xff0c;预览、导出安装插件docx 模板文件内容完整代码…

springmvc redirect 使用https后跳转到了http://域名:443问题处理

最近在处理一个很久之前的项目的时候&#xff0c;由于需要将http升级到https&#xff0c;导致springmvc项目中配置的redirect报错 线上的返回结果是http://abc.test.com:443/jrbac/mobile/wechat.html 通过nginx配置了一下解决了&#xff0c;记录一下 location /jrbac {proxy…

用空闲时间做了一个小程序-二维码生成器

一直在摸鱼中赚钱的大家好呀~ 先向各位鱼友们汇报一下情况&#xff0c;目前小程序已经有900的鱼友注册使用过。虽然每天都有新的鱼友注册&#xff0c;但是鱼友增长的还很缓慢。自从国庆前的文字转语音的工具上线到现在已经将近有1个月没有更新小程序了。但是今天终终终终终于又…

【JavaEE】springMVC返回Http响应

目录 一、返回页面二、Controller和ResponseBody与RestController区别三、返回HTML代码⽚段四、返回JSON五、HttpServletResponse设置状态码六、设置Header6.1 HttpServletResponse设置6.2 RequestMapping设置 一、返回页面 步骤如下&#xff1a; 我们先要在static目录下创建…

【新手初学】SQL注入getshell

一、引入 木马介绍&#xff1a; 木马其实就是一段程序&#xff0c;这个程序运行到目标主机上时&#xff0c;主要可以对目标进行远程控制、盗取信息等功能&#xff0c;一般不会破坏目标主机&#xff0c;当然&#xff0c;这也看黑客是否想要搞破坏。 木马类型&#xff1a; 按照功…

验证Linux多进程时间片切换的程序

​​ 一、软件需求 在同时运行多个CPU密集型进程时&#xff0c;需采集以下统计信息&#xff1a; 当前运行在逻辑CPU上的进程ID每个进程的运行进度百分比 实验程序设计要求&#xff1a; 1. 命令行参数 参数说明示例值n并发进程数量3total总运行时长&#xff08;毫秒&…

Spring笔记03-依赖注入

简述: Spring 依赖注入&#xff08;Dependency Injection&#xff0c;DI&#xff09;是 Spring 框架的核心功能之一&#xff0c;它通过将对象的依赖关系交由 Spring 容器来管理&#xff0c;实现了对象之间的解耦&#xff0c;提高了代码的可维护性和可测试性。 构造器注入示例:…

减少采样空间方法 变成后验概率

又 因为后验概率很难计算 --所以通过引入变分分布来近似 后验概率分布 同时 引入 kl散度来度量 近似的效果好不好 什么是kl散度 kl散度带变分&#xff1a; 第一个问题 &#xff1a;积分变期望 问题二&#xff1a;贝叶斯公式 第三个问题&#xff1a;为啥可以独立出来 因为相比…

【keil】单步调试

一、步骤 1、打开stc-isp软件 2.打开keil仿真设置&#xff0c;选择对应的单片机型号 3.点击将所选目标单片机设置为仿真芯片&#xff0c;点击下载&#xff0c;按一下单片机打下载按钮 4.此时已经将仿真程序下载到单片机 5.此时点击options,找到debug选择STC Montor 51 Driv…

【即插即用涨点模块-卷积】SPDConv空间深度卷积,助力小目标与低分辨有效涨点【附源码+注释】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…