C++11 左值 右值

news2024/12/24 9:07:53

什么是左值?什么是左值引用?

左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可以对它赋

值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边定义时const修饰符后的左

值,不能给他赋值,但是可以取它的地址。左值引用就是给左值的引用,给左值取别名

i和j都可以被取地址,因此都是左值:

i和j都是左值引用

什么是右值?什么是右值引用?

右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引

用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能

取地址。右值引用就是对右值的引用,给右值取别名

下面几个不可以被取地址,因此是右值:(右值可以是常数,表达式,函数):

以下几个为右值引用:

左值能否给右值取别名?

如下所示,不可以:

因为右值不能被修改,加引用就可以修改了,对右值来说,这是一种权力的返回广大,因此我们要加const:

右值表达式同理:

右值引用能否给左值取别名?

如下所示,不能:

但是右值可以给mov后的左值取别名:

左值引用使用场景和意义

(1)引用传参,(2)引用返回

前面我们可以看到左值引用可以引用左值和又可以引用右值,那为什么C++11还要提出右值引

用呢?是不是化蛇添足呢?下面我们来看看左值引用的短板,右值引用是如何补齐这个短板的!

场景1:

我们模拟一个string,命名空间为bit。

bitstring.cc · 孙鹏宇/孙鹏宇的第一个仓库 - 码云 - 开源中国 (gitee.com)

接下来我们在模拟的string里写一个to_string函数(请先将bit命名空间里的移动构造函数,移动赋值函数注释掉):

场景1是没办法用左值引用返回的:

强行左值引用返回:

原因:

ret是to_string()的局部变量,出了作用域就会销毁,我们正常返回是对ret做了个拷贝,返回的是拷贝。如果强行用引用返回,相当于把ret的别名返回,ret出了作用域就销毁了,别名自然也销毁了。

只有出了作用域变量还在,才能用左值引用返回!

ret出了作用域就会销毁,所以需要拷贝构造创建一个临时变量,返回临时变量。

临时变量返回之后s去接受,又需要一次赋值拷贝。两次拷贝代价很大:

优化

ret对象无法拯救,但是ret指向的资源可以拯救!

右值分为普通右值将忘右值列如上文出了作用域就要销毁的就叫做将亡值

对于将忘值,既然它都要快要灭亡了,那我们就直接拿它的资源来用,如下:

交换资源比做深拷贝代价要小。

右值插入

C++11给STL容器的 插入 接口提供了 右值插入版本,例如:
list:set:

等等。

什么情况下用左值插入,什么情况下用右值插入?

如下,list左值插入调用了一次深拷贝,list右值插入调用了两次移动构造,虽然是两次移动构造,但是代价也比一次深拷贝小

如果没有移动构造函数,右值插入会有两次深拷贝

接下来不用库的list,用我们自己模拟实现的list实现右值引用。

首先是以前写的没有右值引用功能的模拟实现list:list.h · 孙鹏宇/孙鹏宇的第一个仓库 - 码云 - 开源中国 (gitee.com)

在原先模拟实现的list基础上增加 C++11右值插入版本:

我们先用库的list指行如下操作:

(1)插入左值s1,(2)调用to_string,(3)插入字符串"222222"。

发现,只有左值插入时才会产生深拷贝,剩下的全是调移动构造:

然后我们调自己写的list指向同样的操作:

发现只调了一次移动构造,剩下全是深拷贝!

这是什么原因呢?
 

通过调试,发现调用to_string确实调用的是移动构造右值尾插:

然后我们可以看一下 insert调的是哪个版本的insert()函数。F11进入insert()函数,如下:

我们发现竟然调了左值插入

总结

右值不能修改,但是右值的引用可以修改(右值的引用本质调用移动拷贝,如果右值引用不能被修改,怎么转移资源?),即右值的引用为左值:

这样就可以解释为什么最后调到了  左值插入:

解决方法:

我们可以move一下,就可以调 右值插入了:

运行,发现还是只调了一次移动构造:

原因:

insert()会把x传给new,new会调构造函数,构造函数是左值引用:

所以我们还需要再写一个右值引用版本的构造函数:

不能写两个全缺省的构造函数,编译器不知道调哪个,我们把右值引用全缺省构造函数改一下:

原因:

右值引用的属性是左值,我们需要再move一下把它变回右值:

完美转发

模板中的&& 万能引用

传统的引用来看这个是右值引用,但实际上它既可以是左值引用可以是右值引用,因为它是模板

// 模板中的&&不代表右值引用而是万能引用,其既能接收左值又能接收右值。
// 模板的万能引用只是提供了能够接收同时接收左值引用和右值引用的能力,
// 但是引用类型的唯一作用就是限制了接收的类型后续使用中都退化成了左值
// 我们希望能够在传递过程中保持它的左值或者右值的属性, 就需要用我们下面学习的完美转发

 写一段如下代码:

 传参调用一下:

结果:

为什么全是左值引用?

因为右值的引用是左值,那么move一下呢?

也不行,我们期望保持值原本的属性,即:是左值就调左值引用是右值就调右值引用

 这个时候我们就要用到完美转发这个东西:

代码托管

右值引用和移动语义 · 孙鹏宇/孙鹏宇的第一个仓库 - 码云 - 开源中国 (gitee.com)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

亚马逊云科技re:Invent大会,助力安全构建规模化生成式AI应用

2023亚马逊云科技re:Invent全球大会进入第三天,亚马逊云科技数据和人工智能副总裁Swami Sivasubramanian博士在周三的主题演讲中,为大家带来了关于亚马逊云科技生成式AI的最新能力、面向生成式AI时代的数据战略以及借助生成式AI应用提高生产效率的精彩分…

变量和引用

变量和引用 2.1.深入认识变量 2.1.1.什么是变量 变量是在程序中保存用户数据的一段内存存储空间,变量名是内存空间的首地址 变量三要素:名称、类型、值 2.1.2.变量的名称 组成: 字母、数字、下划线组成,不能以数字开头 变量名称的长…

Android 获取应用签名

Android 获取应用签名 本文主要讲下在android中如何获取应用签名. 也方便平时用来区分一个应用是不是原包应用. 1: 通过PackageManager获取签名信息 首先,通过packageManager获取到指定应用的PackageInfo. 这里需要传入的flag是PackageManager.GET_SIGNATURES /*** {link P…

scrapyd及gerapy的使用及docker-compse部署

一、scrapyd的介绍 scrapyd是一个用于部署和运行scrapy爬虫的程序,它允许你通过JSON API(也即是web api)来部署爬虫项目和控制爬虫运行,scrapyd是一个守护进程,监听爬虫的运行和请求,然后启动进程来执行它们 scrapyd的安装 scr…

蓝桥第一期模拟总结

文章目录 1.动态的 Tab 栏2.地球漫游3.迷惑的this4.燃烧卡路里5.魔法失灵了6.年龄统计 所有题目链接 1.动态的 Tab 栏 本题要实现一个tab栏固定效果,看见题目就想到css中的 position: fixed; 尝试了很久都没能实现效果,后来又想到了粘性定位 position: …

网络编程之套接字

端口 && IP 在学习套接字编程之前,我们必须了解一下前缀知识。首先是IP和端口的作用。 在这之前,我们要明白一件事。那就是把数据从一台主机发送到另一台主机,是目的吗???当然不是!&a…

TOP-K问题和向上调整算法和向下调整算法的时间复杂度问题的分析

TOP-K问题 TOP-K问题:即求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大 比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等 对于Top-K问题,能想到的最简单直接的方式就是排序,但是…

聊聊测试for Jeffky

什么是测试 测试是一个系统性的过程,它涉及到在已开发的软件中执行程序、应用工具和技术来评估其质量、功能和性能。这个过程的目的是发现并纠正程序中的错误,提高软件的可靠性和稳定性,以满足用户的需求。 测试的分类 什么是自动化测试 自动…

Android Termux 安装Kali Linux 或 kali Nethunter史诗级详细教程

Android Termux 安装Kali Linux 或 kali Nethunter史诗级详细教程 一、Termux配置1、下载安装2、配置存储和换源3、基本工具安装 二、Kali Linux安装1、下载安装脚本2、更换apt源3、图形化安装 三、Kali Nethunter安装1、下载安装脚本2、更换apt源3、图形化连接 四、报错汇总1、…

五、关闭三台虚拟机的防火墙和Selinux

目录 1、关闭每台虚拟机的防火墙 2、关闭每台虚拟机的Selinux 2.1 什么是SELinux

《第一行代码:Android》第三版4.2常用控件的使用方法(1)

概述 本文主要讲解常用控件的使用&#xff0c;包括&#xff1a;TextView、Button、EditText、ImageView、ProgressBar、AlertDialog。 布局文件 布局文件是activity_main.xml,内容如下&#xff1a; <?xml version"1.0" encoding"utf-8"?> <…

Spring Cloud笔记 —— 什么是Spring Cloud?

引言&#xff1a; 在写这篇博客之前&#xff0c;其实吧&#xff0c;博主很久之前有过一段时间的Spring Cloud的案例项目开发经验&#xff0c;就是一个案例项目开发而已&#xff0c;也说不上有多高大上&#xff0c;那个时候&#xff0c;我其实也是从众而已罢了&#xff0c;毕竟现…

Asp.Net Core Web Api内存泄漏问题

背景 使用Asp.Net Core Web Api框架开发网站中使用到了tcp socket通信&#xff0c;网站作为服务端开始tcp server&#xff0c;其他的客户端不断高速给它传输信息时&#xff0c;tcp server中读取信息每次申请的byte[]没有得到及时的释放&#xff0c;导致内存浪费越来越多&#…

WEBAPI返回图片显示在VUE前端

WEBAPI部分 通过nuget安装Opencvsharp &#xff0c;这部分用来做图像处理 在controller中写如下方法&#xff0c;我要对原图进行旋转使用了Opencv&#xff0c;如果不需要旋转可以用注释的代码 [HttpGet(Name "ShowImage")]public async Task<IActionResult> …

基于Java+Swing+Mysql图书管理系统(含实训报告)

基于JavaSwingMysql图书管理系统-含实训报告 一、系统介绍二、功能展示1.用户登陆 四、其他系统实现五、获取源码 一、系统介绍 该系统实现了查看登录界面、主页界面、图书类别管理、用户借阅记录、用户图书查询、用户图书归还、用户信息修改。 运行环境&#xff1a;idea、jd…

selenium三猛士

selenium包括三个项目&#xff0c;分别是&#xff1a;Selenium WebDriver,Selenium IDE&#xff0c;Selenium Grid。 Selenium WebDriver Selenium WebDriver是客户端API接口&#xff0c;测试人员通过调用这些接口&#xff0c;来访问浏览器驱动&#xff0c;浏览器再访问浏览器…

亚马逊云科技 re:Invent 2023:科技前沿风向标,探索未来云计算之窗

文章目录 一、前言二、什么是亚马逊云科技 re:Invent&#xff1f;三、亚马逊云科技 re:Invent 2023 将于何时何地举行四、亚马逊云科技 re:Invent 2023 有什么内容&#xff1f;4.1 亚马逊云科技 re:Invent 2023 主题演讲4.2 亚马逊云科技行业专家探实战 五、更多亚马逊云科技活…

竞赛选题 : 题目:基于深度学习的水果识别 设计 开题 技术

1 前言 Hi&#xff0c;大家好&#xff0c;这里是丹成学长&#xff0c;今天做一个 基于深度学习的水果识别demo 这是一个较为新颖的竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-senior/pos…

深入解析SpringBoot的请求响应机制

SpringBootWeb请求响应 前言1. 请求1.1 Postman介绍 1.2 简单参数1.2.1 原始方式1.2.2 SpringBoot方式1.2.3 参数名不一致 1.3 实体参数1.3.1 简单实体对象1.3.2 复杂实体对象 1.4 数组集合参数1.4.1 数组1.4.2 集合 1.5 日期参数1.6 JSON参数1.7 路径参数 2. 响应2.1 Response…

SATA模块物理层OOB信号分析总结(三)

目录 一、简介二、总体解析2.1 OOB作用2.2 OOB信号的组成2.3 总体phy link过程2.4 整体PHY LINK Trace2.5 PHY LINK状态查询 三、其他相关链接1、SATA模块之HBA卡开发总结&#xff08;一&#xff09;2、SATA信息传输FIS结构总结&#xff08;二&#xff09;3、PCIe物理层总结-PC…