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,一经查实,立即删除!

相关文章

LLMs之CriticGPT:CriticGPT的简介、安装和使用方法、案例应用之详细攻略

LLMs之CriticGPT&#xff1a;CriticGPT的简介、安装和使用方法、案例应用之详细攻略 目录 CriticGPT的简介 1、简介 2、CriticGPT的方法 2.1、CriticGPT的训练方法 2.2、CriticGPT的批评生成方法 3、局限性 4、后续步骤 CriticGPT的安装和使用方法 CriticGPT的案例应用…

“proxy_pass“ directive is duplicate

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

AI并不是开发者的敌人,而是帮助他们实现更高效工作的得力助手。

AI是在帮助开发者还是取代他们&#xff1f; 在软件开发领域&#xff0c;生成式人工智能&#xff08;AIGC&#xff09;正在改变开发者的工作方式。无论是代码生成、错误检测还是自动化测试&#xff0c;AI工具正在成为开发者的得力助手。然而&#xff0c;这也引发了对开发者职业前…

基于主流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…

Sping源码总览

源码地址&#xff1a;https://github.com/spring-projects/spring-framework 仓库地址&#xff1a;https://gitcode.net/qq_42665745/spring/-/tree/master 文章目录如下&#xff1a; 实现一个简单的Bean容器Bean 的定义、注册、获取Bean有参构造实例化Bean属性注入资源加载器…

C++11使用std::future和std::promise实现线程同步和异步通信

std::future 和 std::promise 是 C11 引入的标准库特性&#xff0c;用于实现线程间的异步通信和同步。它们提供了一种机制&#xff0c;使一个线程能够生成一个值或异常&#xff0c;并让另一个线程获取这个值或异常。 (线程A中设置结果) std::promise 用于设置异步操作的结果(线…

【Jupyter Notebook与Git完美融合】在Notebook中驾驭版本控制的艺术

标题&#xff1a;【Jupyter Notebook与Git完美融合】在Notebook中驾驭版本控制的艺术 Jupyter Notebook是一个流行的开源Web应用程序&#xff0c;允许用户创建和共享包含实时代码、方程、可视化和解释性文本的文档。而Git是一个广泛使用的分布式版本控制系统&#xff0c;用于跟…

关于C#在WPF中如何使用“抽屉”控件

关于C#在WPF中如何使用“抽屉”控件 1.前提准备2.XAML代码3.对应的C#代码4.显示效果1.前提准备 需要引用MaterialDesign控件库,关于如何引用,请参照文章——关于C#如何引用MaterialDesign控件库 2.XAML代码 <Window x:Class="MaterialDesign_Test.MainWindow"…

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

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

Http接口RestSharp中StatusCode返回0, 但服务器或本地postman获取应答正常(C#)

我的本地和其他服务器用同一段代码都可以访问&#xff1a; 原代码&#xff1a; RestClient client new RestClient(url); client.Timeout -1; RestRequest request new RestRequest(Method.POST); request.AddHeader("Authorization", "Bearer " acc…

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;接下来我将会…

框架为我们做了什么?

1. SpringBoot 1.1 web服务器 Spring Boot 的 web 服务器原理主要基于其嵌入式服务器的概念&#xff0c;这意味着它内嵌了一个 web 服务器&#xff0c;无需部署到外部服务器上。Spring Boot 内嵌了如 Tomcat、Jetty 或 Undertow 等 servlet 容器。 1.2 servlet Servlet&…

【鸿蒙学习笔记】创建自定义组件

官方文档&#xff1a;创建自定义组件 目录标题 自定义组件的基本结构&#xff11;・struct 自定义组件名 {...}&#xff20;ComponentEntry &#xff11;・ &#xff12;・ &#xff13;・ &#xff14;・ &#xff15;・ &#xff16;・ &#xff17;・ &#xff18;・ &…

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…