C++: 左值引用和右值引用

目录

概念:

理解:

 左值引用,右值引用

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

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

引用的意义是什么?

左值和右值对自定义类型有什么区别吗?

move的妙用!

没有优化的左值传输:

 临时变量是必然产生的!

 右值引用本身是左值!

主要原因:

右值引用的底层 和左值引用的底层: 

右值能否被改变?

概念:

传统的C++语法中就有引用的语法,而C++11中新增了的右值引用语法特性,所以从现在开始我们 之前学习的引用就叫做左值引用。无论左值引用还是右值引用,都是给对象取别名。

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

左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可以对它赋 值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。

定义时const修饰符后的左 值,不能给他赋值,但是可以取它的地址。

左值引用就是给左值的引用,给左值取别名。

int main()
{// 以下的p、b、c、*p都是左值
int* p = new int(0);int b = 1;const int c = 2;// 以下几个都是常见的右值
10;x + y;fmin(x, y);return 0;}

理解:

在以往较为浅薄的理解中,左值是可以进行修改的,右值是无法进行修改的

例如,图中的a是变量可以进行修改是左值,但10是常数不能进行修改是右值,但不完全是这样的结果:又如下图所示,a在第一行代码中是左值,在第二行代码中又充当了右值,所以左值和右值不能如此轻易的划分。

又如:加上了const的c是不允许被修改的,所以c是左值还是右值?答案是:c是左值!

因此,最后我们可以总结出一个结论, 可以取地址的是左值,不能取地址的是右值。

同时我们也需要注意,左值代表的不一定是一个数值,也可也是一个表达式。

例如:

*p 
*p 是一个左值vector<int> v(10,1);
v[1];
v[1] 是一个左值

凡是能取到地址的都算是左值! 

而右值就是取不到地址的,同样右值也可以是一个表达式,且同时,临时变量、匿名对象、临时对象统统都是右值!

都是右值 

 左值引用,右值引用

引用就是取别名!左值引用就是给左值取别名,右值引用取别名!

int main()
{// 以下的p、b、c、*p都是左值
int* p = new int(0);int b = 1;const int c = 2;// 以下几个是对上面左值的左值引用int*& rp = p;int& rb = b;const int& rc = c;int& pvalue = *p;double x = 1.1, y = 2.2;
// 以下几个都是常见的右值
10;x + y;fmin(x, y);
// 以下几个都是对右值的右值引用int&& rr1 = 10;double&& rr2 = x + y;double&& rr3 = fmin(x, y);
// 这里编译会报错:error C2106: “=”: 左操作数必须为左值10 = 1;x + y = 1;fmin(x, y) = 1;return 0;
}

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

答案是不可以!但是加上const可以!

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

答案也是不可以!但是需要把左值加上move进行使用后才行!

所以左右值引用 可以对左右值进行取别名,但是要有条件!

引用的意义是什么?

  • 减少拷贝!提高效率!传值、传参、传引用返回 都可以使用引用,这是左值引用的常见场景!
  • 但是左值引用没有彻底解决返回值的问题,右值引用就是修补这一块内容。
  • 因为如果是一个临时对象,或者局部对象,则不能使用引用返回!因为出了作用域地址就会被销毁,所以没有用!而这种问题也不能直接使用右值引用进行返回,右值引用返回不是这样用的! 

例如:

在主函数调用的时候,会在返回的时候进行临时变量的构造然后再加上拷贝构造把数值从临时变量中进行拷贝导赋值变量中,然后C++11后面优化成了一个直接获取!

 这里无论是加左值引用还是右值引用都没有效果且会报错,因为str是局部变量被销毁了!地址不存在了!因为出作用域了!

为了解决这种问题,增加一个右值引用的构造函数,而被右值引用修饰的构造叫做移动构造!

有了移动构造,编译器会进行选择,如果返回的时候是左值,那么编译器就会去选择拷贝构造,如果是右值,那么就会 选择移动构造

左值和右值对自定义类型有什么区别吗?

自定义类型的右值基本都是匿名对象、传值返回的临时对象。

然后右值又有细分,分为纯右值和将亡值,基本上内置类型的右值都是纯右值,而自定义类型的右值基本都是将亡值。

对于局部变量来说,它的左值只能是老实的开辟空间然后被利用完被拷贝完后销毁空间,

而对于局部变量来说,它的右值(将亡值),它会利用空间! 将拷贝数值的空间和临时变量的空间进行交换!

 有了移动构造后,在传值时,会强行把左值变成右值,强行使用了move (可以不在返回时加上move 编译器会做处理!)/可以看出str虽然是左值,但是和将亡值没什么区别

 然后会调用两次移动构造,但是编译器直接转移资源,一步到位!以前需要进行拷贝,但是右值的移动构造,将被赋值的数值强行和右值进行交换!

移动构造为什么叫移动构造,是因为它移动将亡值对象的资源!!!!把将亡值的资源转移到被赋值调用的数据上!

严格来说,移动构造是延长了将亡值 所占据的资源数据的生命周期,而不是延长了将亡值所处在空间地址的生命周期。因为是转移资源,所以移动构造的代价是极低的!

move的妙用!

可以看出s1的数据被移动到了s3 这就是move的功能!  

没有优化的左值传输:

没有优化的传输其实就是仙拷贝构造在赋值拷贝,就如下图中的写法,导致编译器无法进行优化!

 优化:进行优化的左值传输!一次构造和一次拷贝构造,最后被编译器优化成了一次拷贝构造!

 临时变量是必然产生的!

 临时对象是必然产生的,这个临时对象是在寄存器的,但是寄存器非常的小,所以当对象数据过大时,会把临时对象放到两个数据的栈帧中:如下图所示的绿色框框就是处在main和to_string两个栈帧之间!

这种编译器无法进行优化的,可以使用move进行转化成移动构造函数,将其变成一次移动构造,一次移动赋值!

str在传输时会给一个临时对象,然后把临时对象的数据(空)的数据和 传输的数据进行数据之间的交换,然后在临时赋值的时候,因为在赋值之前进行初始化,所以会把初始化的那个空间和临时对象内部的数据再一次进行交换,然后完成移动赋值!

 右值引用本身是左值!

右值和右值引用,求s1是右值还是左值?左值!已知std::string(“11111111”)是右值

但是右值引用是左值!有地址!右值引用本身是左值!

主要原因:

右值有一个特点,本身是不能改变的,因为如果使用了别名,那如果别名也不能改变,那如何做资源转移?

可以看出右值的资源转移主要是因为swap如转移的过程中数值不能进行改变,也就是右值引用的数据不能改变,那么将无法进行资源的转移!所以也就可以得出,右值引用是左值!

右值引用的底层 和左值引用的底层: 

右值引用和左值引用的底层都是指针,都是取匿名空间的地址!所以右值真的没有地址吗?那右值存哪里?总要存储吧!所以右值是有地址的,只是不能拿取这个地址罢了!取不到这个地址罢了! 

右值能否被改变?

s5是可以左值引用s1的!但是s6是不能直接左值引用的!但是可以使用强制转化:

可以资源转移到s7!所以右值能否改变呢!可以的!如果不用强转呢?

先给一个右值引用,然后在左值引用,本质就是右值引用底层是指针,且底层还是有空间存储的!

和上面的s5和s1的操作一样!类似于交换!

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

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

相关文章

“proxy_pass“ directive is duplicate

后面发现是nginx.conf里面proxy pass这里有两个&#xff0c;注释其中一个并重新运行即可&#xff01;

基于主流SpringBoot进行JavaWeb开发的学习路线

目录 一、学习路线 &#xff08;1&#xff09;第一部分&#xff08;Web前端开发的技术栈&#xff09; &#xff08;2&#xff09;第二部分&#xff08;Web后端开发&#xff09; 二、学习之后必备的技能 三、学习Web开发的基础与未来的收获 学完这一类知识目标&#xff1a;…

Mybatis-01 原理

一. JDBC式编程 在 jdbc 编程中&#xff0c;我们最常用的是 PreparedStatement 式的编程&#xff0c;我们看下面这个例子&#xff1b; Connection conn null; PreparedStatement ps null; ResultSet rs null;try {// 1. 注册驱动Class.forName("com.mysql.jdbc.Drive…

化身成羊:关于羊的词群探析

在西方的神话故事中&#xff0c;像主神宙斯&#xff0c;或者基督教义中的上帝&#xff0c;通常都有化身成羊的形象。 那为什么会这样呢&#xff1f; 一、什么是神话(myth)&#xff1f; 神话&#xff0c;正式的用词是 mythology&#xff1a; mythology n.神话&#xff1b;神话…

Echarts中的折线图,多个Y轴集中在左侧(在Vue中使用多个Y轴的折线图)

简述&#xff1a;在 ECharts 中&#xff0c;创建一个带有多个 Y 轴的折线图&#xff0c;并且将这些 Y 轴都集中显示在图表的左侧&#xff0c;可以通过合理配置 yAxis 和 series 的属性来实现。简单记录 一. 函数代码 drawCarNumEcs() {// 初始化echarts图表,并绑定到id为"…

网络安全设备——探针

网络安全设备探针是一种专门用于网络安全领域的工具&#xff0c;它通过对网络流量进行监控和分析&#xff0c;帮助发现和防止网络攻击。以下是对网络安全设备探针的详细解释&#xff1a; 定义与功能 定义&#xff1a;网络安全设备探针是一种设备或软件&#xff0c;它通过捕获…

【docker】运行阶段遇到的问题

目录 1、查询docker 下挂载了哪些工具 2、docker中的简单命令 3、实际场景应用&#xff08;redis&#xff09; 目前工作中仅用到了redis,所以没有太多经验可以交流&#xff0c;暂时仅将我目前遇到的进行发布。还请见谅。 1、查询docker 下挂载了哪些工具 docker ps -a 或者…

Vue组件如何“传话”?这里有个小秘诀!

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;vue篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来vue篇专栏内容:vue-组件通信 目录 Vue组件通信 &#xff08;1&#xff09; props / $emit 1. 父组件向子组件传…

适合职场小白的待办事项管理方法和工具

刚入职场那会儿&#xff0c;我每天都像只无头苍蝇&#xff0c;忙得团团转却效率低下。待办事项像潮水般涌来&#xff0c;会议、报告、客户跟进……每一项都像是悬在头顶的利剑&#xff0c;让我焦虑不堪。我深知&#xff0c;管理好待办事项是职场生存的必修课&#xff0c;但该如…

内衣洗衣机哪个牌子好用?倾力推荐四大热门产品,质量放心

在当今社会&#xff0c;内衣洗衣机已经成为每个家庭必不可少的家电之一。但由于市场上的内衣洗衣机品牌和型号繁多&#xff0c;对于消费者来说&#xff0c;选择一款实用、性价比高的内衣洗衣机是非常重要的。那么&#xff0c;内衣裤洗衣机哪个品牌最好&#xff1f;接下来我将会…

Python | Leetcode Python题解之第206题反转链表

题目&#xff1a; 题解&#xff1a; # Definition for singly-linked list. # class ListNode: # def __init__(self, val0, nextNone): # self.val val # self.next next class Solution:def reverseList(self, head: Optional[ListNode]) -> Optio…

VulnHub靶场之DarkHole_1

1 信息收集 1.1 主机发现 arp-scan -l 主机IP地址为&#xff1a;192.168.1.17 1.2 端口和服务扫描 nmap -sS -sV -A -T5 -p- 192.168.1.17 开放22&#xff0c;80端口 1.3 目录扫描 dirsearch -u 192.168.1.17 2 渗透 2.1 访问端口 2.2 注册账号 暴力破解不现实&#…

Python爬取国家医保平台公开数据

国家医保服务平台数据爬取python爬虫数据爬取医疗公开数据 定点医疗机构查询定点零售药店查询医保机构查询药品分类与代码查询 等等&#xff0c;数据都能爬 接口地址&#xff1a;/ebus/fuwu/api/nthl/api/CommQuery/queryFixedHospital 签名参数&#xff1a;signData {dat…

java版本ERP管理系统源码 Spring Cloud ERP_ERP系统_erp软件_ERP管理系统

在当今数字化时代&#xff0c;企业对高效、稳定且易于扩展的管理系统的需求日益增长。为了满足这一需求&#xff0c;我们精心打造了一款基于Java技术的ERP&#xff08;Enterprise Resource Planning&#xff09;管理系统。该系统充分利用了Spring Cloud Alibaba、Spring Boot、…

python-计算矩阵边缘元素之和(赛氪OJ)

[题目描述] 输入一个整数矩阵&#xff0c;计算位于矩阵边缘的元素之和。 所谓矩阵边缘的元素&#xff0c;就是第一行和最后一行的元素以及第一列和最后一列的元素。输入&#xff1a; 输入共 m 1 行。 第一行包含两个整数 m, n (1 < m,n < 100) &#xff0c;分别为矩阵的…

VDS虚拟导播切换台软件

VDS 导播软件是一款功能强大的虚拟导播系统软件&#xff0c;具有全媒体接入、播出内容丰富、调音台、快捷切播与导播键盘、云台控制等特点&#xff0c;同时支持向多个平台直播推流。以下是一些常见的 VDS 导播软件特点&#xff1a; 1. 全媒体接入&#xff1a;支持多种设备和网…

【APK】SDKManager运行后闪退

本地JDK已安装&#xff0c;且配置了环境变量&#xff0c;未安装 android studiio 问题描述&#xff1a;右键以管理员身份运行 SDKManager&#xff0c;终端窗口闪退 问题原因&#xff1a;未找到正确的Java路径 解决办法&#xff1a; 1.修改tools目录下的 android.bat 文件&am…

langchain 入门中篇:数据封装,Memory 封装

数据的处理流程可以看一张图来帮助理解 数据来源可以是网络&#xff0c;可以是邮件&#xff0c;可以是本地文件 经过 Document Loaders 加载&#xff0c;再在 Transform 阶段对文档进行 split, filter, translate, extract metadata 等操作&#xff0c;之后在 Embed 阶段进行向…

Keil用ST-LINK下载STM32程序后不自动运行

之后程序可以运行了&#xff0c;但是串口还没有输出&#xff0c;在debug模式下都是ok的。

加权 KNN 算法的原理与详解

加权kNN&#xff0c;k近邻算法的增强改进版本。 加权KNN算法 近邻算法&#xff08;k-Nearest Neighbors, kNN&#xff09;是一种用于分类和回归的非参数方法。它的基本思想是“看邻居”&#xff0c;即通过查找离目标点最近的 K 个数据点&#xff0c;来判断目标点的类别或数值。…