C++程序设计——右值引用

news2024/10/6 14:32:02

一、右值引用概念

引用:

        C++98中提出了引用的概念,引用即别名,引用变量与其引用实体共用同一块内存空间,而引用的底层是通过指针来实现,因此使用引用,可以提高程序的可读性。

右值引用(类型&& 右值):

(1)为了提高程序的运行效率,C++11中引入了右值引用;

(2)右值引用也是别名;

(3)只能对右值进行引用。

(4)右值有了名字后,就成了一个普通变量,也就是左值。

二、左值与右值

        左值与右值是C语言中的概念,但C标准并没有给出严格的区分方式。一般认为:可以放在=的左边,或能够取地址的称为左值;只能放在=右边的,或不能取地址的称为右值。但不一定完全正确。

一般认为:

(1)普通类型的变量,因为有名字,可以取地址,都认为是左值。

(2)const修饰的常量,不可修改,只读类型,理论上应该按照右值对待,但因为其可以取地址,C++11认为其是左值。

(3)如果表达式的运行结果是一个临时变量或者对象,认为是右值。

(4)如果表达式运行的结果或单个变量是一个引用,认为是左值。

C++11对右值进行了严格区分:

(1)C语言中的纯右值,比如:10,a+b;

(2)将亡值,比如:表达式的中间结果、函数按照值的方式进行返回。

三、引用与右值引用比较

C++98中的普通引用与const引用,在其引用实体上的区别:

(1)普通引用只能引用左值,不能引用右值;

(2)const引用既可以引用左值,也可以引用右值。

C++ 11中右值引用:

(1)只能引用右值;

(2)一般情况不能直接引用左值。

 (3)右值引用引用左值方法:使用move函数进行转换。

四、值形式返回对象的缺陷

        如果一个类中涉及到资源的管理,用户必须显示的提供拷贝构造函数、赋值运算符重载、析构函数,否则编译器将会自动生成默认的成员函数。而当遇到拷贝对象或对象之间相互赋值的情况时,就会出现一些问题,比如:

class String {
public:
	String(const char* str = "") {
		if (nullptr == str) {
			str = "";
		}
		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}
	String(const String& s)
		: _str(new char[strlen(s._str) + 1])
	{
		strcpy(_str, s._str);
	}

	String& operator=(const String& s) {
		if (this != &s) {
			char* temp = new char[strlen(s._str) + 1];
			strcpy(temp, s._str);
			delete[] _str;
			_str = temp;
		}
		return *this;
	}
	String operator+(const String& s) {
		char* temp = new char[strlen(_str) + strlen(s._str) + 1];
		strcpy(temp, _str);
		strcpy(temp + strlen(_str), s._str);
		String result(temp);
		delete[] temp;
		return result;
	}

	~String() {
		if (_str) {
			delete[] _str;
			_str = nullptr;
		}
	}

public:
	char* _str;
};

int main() {
	String s1("hello ");
	String s2("world");
	String s3;
	s3 = s1 + s2;
}

        在执行s3 = s1 + s2时,其中operator+是以值形式返回。那么result在返回前,就必须创建一个临时对象,临时对象创建好后,result就被销毁了,然后使用返回的临时对象去赋值s3,赋值完成后,临时对象就被销毁掉。

        可以发现,result、返回的临时对象、s3每个对象创建后,都有自己独立的空间,且它们存放的内容也相同,相当于创建了三个内容完全相同的对象,对于空间是一种浪费,程序的效率也较低。

优化思路:

        如果可以将result的空间转移给临时对象,临时对象在赋值s3时,再将空间转移给s3,这样就相当于只开辟了一次空间。

实现方法:

        可以发现,result相对于临时对象,临时对象相对于s3来说,都是将亡值,也就是右值。所以我们只需要实现一个移动构造函数和移动赋值函数即可,这样对于右值,则会自动调用移动函数,采用转移的方式进行构造或赋值。

注意:

(1)移动构造和移动赋值函数的参数不能设置为const类型的右值引用,否则资源无法转移导致移动语义失效。

(2)C++11之后,类中默认的成员函数就新添加了移动赋值、移动构造两个成员函数,同理若用户自己没有实现,编译器会默认生成,只不过默认生成的也是采用浅拷贝的方式实现的,所以当类中涉及到资源的管理时,也需要自己显示定义实现。

五、右值引用引用左值

        按照语法定义,右值引用只能引用右值,但有些情况下,也需要用右值去引用左值实现移动语义。

        当需要用右值引用引用左值时,可以通过move函数将左值转化为右值。C++11中,std::move()函数,它并不是什么搬移功能,唯一的功能就是将一个左值强制转化为右值,然后实现移动语义。

应用场景示例:

        比如以上代码,移动构造中,我们希望的是将s中的资源 全部转移到新对象中,但是s虽然是右值,但编译器并不认为s中的_name、_sno是右值,因为它们有自己的名字、可以对它们取地址,所以在初始化列表初始化时,并不会直接转移,而是会调用String中的拷贝构造函数。

        所以此时就需要我们使用move函数,显示的告诉编译器将s中的_name、_sno当中右值处理,这样在初始化时就会选中去调用String的移动构造函数。

 

应用反例:

六、完美转发

1. 概念

        完美转发是指在函数模板中,完全依照模板的参数的类型,将参数传递给函数模板中调用的另外一个函数。

所谓完美:

        函数模板在向其他函数传递自身参数时,如果相应实参是左值,它就应该被转发为左值;如果相应实参是右值,它就应该被转发为右值。

2. 目的

        保留其他函数对转发来的参数的左右值属性,进行不同的处理。

比如:

        函数func针对参数的左右值属性不同,有不同的处理方式,所以希望函数模板repost在转发参数时,保留其左右值属性,但通过以上写法是不能达到目的的,除法针对左右值属性,编写两个函数模板,但是这又降低了代码的复用性。

        所以希望能够有一种方法,能够实现repost在转发参数时,保留其左右值属性,即完美转发。

3. 实现

(1)将模板函数(包括类模板和函数模板)的参数书写成“T&& 参数名”的形式,这样模板函数既可以接收左值,也可以接收右值引用。(注意:普通函数不行)

(2)C++11提供了模板函数std::forward<T>(参数),用于转发参数。如果参数是左值,转发后仍是左值,如果参数是右值引用,转发后仍是右值引用。

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

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

相关文章

校园商城项目自制面经

ware-仓库 目录 ES 为什么redis快 为什么ES搜索快&#xff1f; 怎么理解es的倒排索引 简单看SpringCache的api Feign怎么用的 gateWay实现前端和后端的跨域请求&#xff1a; 三级分类&#xff1a; 网站的数据上传&#xff1a; JSR303校验 自定义校验功能 ES&#xf…

空间复杂度

概念 空间复杂度&#xff1a;是对一个算法在运行过程中临时占用存储空间大小的量度。 空间复杂度和时间复杂度的表示方法是一样的&#xff0c;也使用大O渐进表示法&#xff0c;计算规则基本相似。空间复杂度计算的并不是程序占用的字节大小&#xff0c;而是变量的个数。 大O…

chatgpt+机器人控制器融合(一)

当今机器人技术面临的挑战&#xff0c;以及 ChatGPT 能提供的帮助 目前机器人的操作流是从工程师或技术用户开始&#xff0c;需要他们将任务需求转换为系统代码。工程师会处于工作流程的回路中&#xff0c;他们需要不断编写新的代码和规范来纠正机器人的行为。总得来说&#x…

Faster-RCNN代码解读4:辅助文件解读

Faster-RCNN代码解读4&#xff1a;辅助文件解读 前言 ​ 因为最近打算尝试一下Faster-RCNN的复现&#xff0c;不要多想&#xff0c;我还没有厉害到可以一个人复现所有代码。所以&#xff0c;是参考别人的代码&#xff0c;进行自己的解读。 ​ 代码来自于B站的UP主&#xff08;…

我的创作纪念日:Unity CEO表示生成式AI将是Unity近期发展重点,发布神秘影片预告

PICK 未来的AI技术将会让人类迎来下一个生产力变革&#xff0c;这其中也包括生成型AI的突破性革新。各大公司也正在竞相推出AIGC工具&#xff0c;其中微软的Copilot、Adobe的Firefly、Github的chatGPT等引起了人们的关注。然而&#xff0c;游戏开发领域似乎还没有一款真正针对性…

vector容器

1、vector简介 vector 和 arry 非常相似&#xff0c;唯一存在的不同是 vector 是动态分配内存空间&#xff0c;随着元素的增加空间自动增加&#xff0c;但是 arry 是静态的 wector&#xff1a;单端动态数组容器&#xff0c;只允许在一端进行操作 2、vector的使用 需要引进头…

PyTorch深度学习实战 | 基于多层感知机模型和随机森林模型的某地房价预测

简介&#xff1a; 在现实生活中&#xff0c;除了分类问题外&#xff0c;也存在很多需要预测出具体值的回归问题&#xff0c;例如年龄预测、房价预测、股价预测等。相比分类问题而言&#xff0c;回归问题输出类型为一个连续值&#xff0c;如下表所示为两者的区别。在本文中&…

打造高效自动化测试流程:Jenkins+Allure+Pytest环境搭建和实战

引言 自动化测试已经成为软件开发中不可或缺的一部分。而在自动化测试中&#xff0c;Jenkins、Allure和Pytest这三个工具的组合可以说是非常流行和实用的。 Jenkins作为持续集成工具&#xff0c;可以充分利用其丰富的插件体系来搭建自动化测试环境&#xff1b; Allure则为我们…

怎么把jpg转换成pdf格式?实用又简单的方法来了

在工作和学习中&#xff0c;我们常常需要发送一些重要的图片给别人&#xff0c;这些图片可能包含学习资料或者重要的文件内容。但是发送多个JPG图片既不方便又不直观&#xff0c;所以我们需要将它们转换成PDF格式&#xff0c;以便于发送和查看。如果你不知道如何进行JPG到PDF的…

UI学习路线图2023完整版(适合自学)

作为数字时代中不可或缺的职业之一&#xff0c;UI设计师在今天和未来都有着广阔的职业前景。UI设计师有高需求行业、薪资高、职位晋升空间大、多样化的工作机会、职业发展空间大等许多优势&#xff0c;也有很多小伙伴想自学UI设计&#xff0c;但是不知道自己怎么学&#xff0c;…

服务器节点之间 如何实现自动化文件同步?

大数据、云计算、物联网的发展&#xff0c;使得企业能够拥有的数据急剧增加。面对快速变化和增长的庞大数据&#xff0c;如何高效地管理、利用数据对于企业来说至关重要。 但是&#xff0c;数据传输模式单一、自动化程度低、传输效率低下等难题&#xff0c;阻碍着企业对其数字…

TensorFlow 1.x 深度学习秘籍:6~10

原文&#xff1a;TensorFlow 1.x Deep Learning Cookbook 协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 本文来自【ApacheCN 深度学习 译文集】&#xff0c;采用译后编辑&#xff08;MTPE&#xff09;流程来尽可能提升效率。 不要担心自己的形象&#xff0c;只关心如…

高级UI之Android事件分发机制原理及源码分析

前言 在 Android 中&#xff0c;事件分发机制是一块很重要的知识点&#xff0c; 掌握这个机制能帮你在平时的开发中解决掉很多的 View 事件冲突问题&#xff0c;这个问题也是面试中问的比较多的一个问题了&#xff0c;本篇就来总结下这个知识点。 事件分发原因 Android 中页…

RK3399平台开发系列讲解(外设篇)Camera OV13850配置过程

🚀返回专栏总目录 文章目录 一、DTS 配置二、驱动说明三、配置原理四、cam_board.xml沉淀、分享、成长,让自己和他人都能有所收获!😄 📢我们以 OV13850/OV5640 摄像头为例,讲解在该开发板上的配置过程。 一、DTS 配置 isp0: isp@ff910000 {…status = "okay&quo…

R-CNN(Region with CNN feature)

目录 1. 介绍 2. R-CNN 2.1 SS(Selective Search) 算法 生成候选框 2.2 CNN 提取特征 2.3 SVM 分类 非极大值抑制 2.4 回归器微调候选框 3. R-CNN 的缺点 1. 介绍 目标识别的发展历史如图 2. R-CNN RCNN 是两阶段目标检测的鼻祖&#xff0c;类似于深度学习开山之作Al…

第03章_流程控制语句

第03章_流程控制语句 讲师&#xff1a;尚硅谷-宋红康&#xff08;江湖人称&#xff1a;康师傅&#xff09; 官网&#xff1a;http://www.atguigu.com 本章专题与脉络 流程控制语句是用来控制程序中各语句执行顺序的语句&#xff0c;可以把语句组合成能完成一定功能的小逻辑模…

算法记录 | Day32 贪心算法

122.买卖股票的最佳时机II 贪心算法 思路&#xff1a; 把利润分解为每天为单位的维度&#xff0c;而不是从0天到第3天整体去考虑&#xff01; 那么根据prices可以得到每天的利润序列&#xff1a;(prices[i] - prices[i - 1])…(prices[1] - prices[0])。 如图&#xff1a;…

PyCharm+PyQt5+pyinstaller打包labelImg.exe

0 开头 labelImg是一款标注软件&#xff0c;作为一个开源项目&#xff0c;它的源码可以在github上找到。官方仓库地址为&#xff1a; https://github.com/heartexlabs/labelImg 小白安装时的最新版本编译出来的界面长这样&#xff1a; 之前在小白的博客里&#xff0c;也教过…

Spring学习5

一、代理模式 代理模式就是AOP的底层&#xff01; 1.代理模式的分类 静态代理动态代理2.静态代理 角色分析&#xff1a; 抽象角色&#xff1a;一般使用接口或者抽象类来解决真实角色&#xff1a;被代理的角色代理角色&#xff1a;代理真实角色后&#xff0c;一般会做一些附属操…

走进小程序【七】微信小程序【常见问题总结】

文章目录&#x1f31f;前言&#x1f31f;小程序登录&#x1f31f;unionid 和 openid&#x1f31f;关键Api&#x1f31f;登录流程设计&#x1f31f;利用现有登录体系&#x1f31f;利用OpenId 创建用户体系&#x1f31f;利用 Unionid 创建用户体系&#x1f31f;授权获取用户信息流…