C++学习笔记----8、掌握类与对象(一)---- 对象中的动态内存分配(4)

news2024/9/29 17:32:29

2.4、使用Move语法处理移动

        类的move语法要求一个move构造函数和一个move赋值操作符。这些可以用于编译器,当源对象是一个临时对象在操作完成时就会被析构,你马上就会看到,显式地使用std::move()。move移动内存的属主以及从一个对象到另一个对象的其它资源。从根儿上说是做了一个shallow拷贝,拷贝与交换分配内存和其它资源以名悬浮指针或者资源并且防止内存渗露的属主相结合的数据成员。

        move构造函数与move赋值操作符移动数据成员从一个源对象到一个新的对象,将源对象置于一个有效但处于中间状态 。通常,源对象的数据成员会被置为“null”值,但这并不是一个严格的要求。推荐确保源对象处于一个清晰定义的空状态,在移动操作之后。安全起见,不要用任何移动的源对象,因为这可以会引发没有定义的行为。有些标准库的著名例外就是std::unique_ptr与shared_ptr。标准库显式地指出这些智能指针一定要重置它们的内部指针为nullptr,当从它们移动出,这使得在移动操作之后重用这些智能指针是安全的。

        在实现move语法之前,需要学习一下右值与右值引用。

2.4.1、右值引用

        在c++中,左值是可以占用一个地址的东东,例如,一个命名的变量。名字来自于左值可以出现在赋值的左手边的事实。另一方面,右值,它除了不是一个左值,可以是例如常量,或者临时对象或者值的任何东东。典型地,一个右值就是在赋值操作符的右手边。例如,考虑下面的语句:

int a { 4 * 2 };

        在这个语句中,a是一个左值,它有名字,可以通过&a来得到它的地址。结果是表达式4*2,另一方面,它就是一个右值。它是一个临时值,在语句执行完成后就会被破坏掉。在这个例子中,临时值的一个拷贝被保存在名字叫做a的变量中。

        如果函数返回一个值,调用该函数的结果就是一个右值,一个临时值。如果函数返回一个reference-to-non-const,调用该函数的结果就是一个左值,因为你可以使用该结果在赋值的左手边。

        右值引用是对右值的一个引用。特别地,它是一个在右值是一个临时对象或者一个显式移动使用std::move()的对象的应用概念。右值引用的目的是使得当右值介入的时候可以选择一个特殊的函数重载成为可能。这允许正常的拷贝大的值的操作而不是拷贝指向这些值的指针。

        函数可以通过使用&&作为参数指标的一部分来指定一个右值引用参数。正常情况下,一个临时对象可以看作是一个const type&,但是当有一个使用右值引用的函数重载时,一个临时对象可以被解释成那个重载。下面举例说明。代码首先定义了两个handleMessage()函数,一个接收左值引用,一个接收右值引用:

void handleMessage(string& message) // lvalue reference parameter
{
    println("handleMessage with lvalue reference: {}", message);
}

void handleMessage(string&& message) // rvalue reference parameter
{
    println("handleMessage with rvalue reference: {}", message);
}

        可以用一命名变量作为参数调用handleMessage():

string a { "Hello " };
handleMessage(a);
// Calls handleMessage(string& value)

        因为a是一个命名变量,接收左值引用的handleMessage()函数被调用。通过引用参数handleMessage()所做的任何改变都会改变a的值。

        也可以用一个表达式作为参数来调用handleMessage():

string b { "World" };
handleMessage(a + b);
// Calls handleMessage(string&& value)

        接收左值引用的handleMessage()无法使用,因为表达式a + b的结果是一个临时值,它不是一个左值。在这种情况下,右值引用重载被调用。因为参数是一个临时的,在调用返回后,任何通过引用参数handleMessage()所做的改变都会丢失。

        常量也可以用于handleMessage()的参数。它也会触发对于右值引用重载的调用,因为一个常量不可能为左值(虽然常量可以作为参数传递给reference-to-const参数):

handleMessage("Hello World"); // Calls handleMessage(string&& value)

        如果移除掉接收左值引用的handleMessage()函数,用一个命名变量调用handleMessage(),比如handleMessage(b)就会出现编译错误,因为右值引用参数(string&&)不会连接上左值(b)。可以通过使用std::move()来强制编译器调用右值引用重载的handleMessage()。move()所做的唯一一件事就是将左值引用转化为右值引用;也就是说,它没有进行任何实质上的移动。然而,通过返回一个右值引用,它允许编译器找到接收右值引用的handleMessage()的重载,它就可以执行移动了。下面是一个使用move()的例子:

handleMessage(std::move(b));
// Calls handleMessage(string&& value)

        重要的事情需要多说,命名变量是一个左值。所以,在handleMessage(string&& message)函数中,message右值引用参数自身是一个左值,因为它有一个名字!如果你想传递这个右值引用参数给另一个函数作为右值,就需要使用std::move()来将这个左值转化成右值引用了。例如,假定你添加了如下的带有右值引用参数的函数:

void helper(string&& message) { }

        像下面这样进行调用是编译不成功的:

void handleMessage(string&& message) { helper(message); }

        helper()函数需要一个右值引用,而handleMessage()传递了message,它有一个名字,所以它是一个左值,导致一个编译错误。下面是使用std::move()的正确方式:

void handleMessage(string&& message) { helper(std::move(message)); }

        警告:命名右值引用,比如一个右值引用参数,自身是一个左值,因为它有一个名字!

        右值引用不仅仅限于函数参数。可以声明一个右值引用类型的变量并给其赋值,虽然这种用法不常见。考虑下面的代码,在c++中是不合法的:

int& i { 2 };    // Invalid: reference to a constant
int a { 2 }, b { 3 };
int& j { a + b };    // Invalid: reference to a temporary

        而使用右值引用,下面就是完美的合法:

int&& i { 2 };
int a { 2 }, b { 3 };
int&& j { a + b };

        然而,这样单独的右值引用很少以这种方式使用,也没有什么卵用!

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

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

相关文章

HuggingChat macOS版正式发布!文章内附体验地址!我国打造糖尿病专用AI模型|AI日报

文章推荐 全新豆包AI视频模型发布!实测下的可灵与豆包!原来它们的差距不止一点点... 今日热点 我国团队打造糖尿病专用AI模型 上海交通大学清源研究院MIFA实验室携手复旦大学附属中山医院内分泌科,组建专家团队,联手开发一款名…

Spring Boot项目连接Oracle数据库启动报错:Undefined Error

描述:远程拉下来的代码,配置了maven仓库后,未进行其他修改,自己本地启动报错。 报错现状: 解决:添加参数-Duser.nameuser后,启动成功。 原因分析: 分析一: maven仓…

Altium Designer脚本系统内置函数汇总(2417个)

Altium Designer脚本系统内置函数汇总(2417个) ↑↑↑点击上方蓝字,关注我们! Altium Designer 2013脚本系统内置函数,一共2417个。 这些函数名称复制到Altium Designer 2013脚本编辑器中会自动变为褐红色(#800000),内部函数大部分…

跨境必备:3个必不可少的低预算营销渠道

不管是跨境电商卖家还是外贸从业人员,从个体到企业或品牌,流量都是宣传营销领域的重点。有流量才能让更多的消费者看到自己的产品,从而有机会了解产品并促成转化。 各大跨境电商平台、社交媒体平台和搜索引擎等平台都提供了付费营销功能&…

16.网络编程(下篇)

目录 1.网络编程概述 2.应用软件架构 3.网络编程三要素-IP地址 4.网络编程三要素-端口与协议 5.UDP通信程序 6.TCP通信程序 1.网络编程概述 1.1计算机网络 是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系…

【问题解决】win10日志错误:创建 TLS 客户端凭据时发生致命错误。 内部错误状态为 10013

背景 最近win10死机了一次,查看事件管理器发现有大量的报错:“创建 TLS 客户端凭据时发生致命错误。 内部错误状态为 10013”,如图: 解决 win键搜索internet选项 确定。 原因 参考错误:“ 创建 TLS 客户端凭据…

C++基础知识9 模版进阶

模版进阶 1. 非类型模板参数2. 模板的特化2.1 概念2.2 函数模板特化2.3 类模板特化2.3.1 全特化2.3.2 偏特化2.3.3 类模板特化应用示例 3 模板分离编译3.1 什么是分离编译3.2 模板的分离编译3.3 解决方法 4. 模板总结 1. 非类型模板参数 模板参数分类类型形参与非类型形参。 类…

有些硬盘录像机接入视频汇聚平台EasyCVR后通道不显示/显示不全,该如何处理?

EasyCVR视频监控汇聚管理平台是一款针对大中型项目设计的跨区域网络化视频监控集中管理平台。该平台不仅具备视频资源管理、设备管理、用户管理、运维管理和安全管理等功能,还支持多种主流标准协议,如GB28181、RTSP/Onvif、RTMP、部标JT808、GA/T 1400协…

C#获取变量的数据类型_C#获取对象的数据类型

C#中的数据类型用 Type 类描述,具体的类型是 Type的对象 一、object.GetType() 对象.GetType()-----对象不能为null,否则运行报错; 通用的获取类型方式 底层对象获取类型,所有的对象,变量获取类型,GetType(); 返回的…

JAVA打造全球商品集散地国际版多商户商城系统小程序源码

打造全球商品集散地 —— 国际版多商户商城系统 🌍【开篇:连接世界,触手可及】🌍 在这个全球化的时代,购物不再受地域限制,每一个消费者都渴望能轻松买到来自世界各地的优质商品。而“打造全球商品集散地”…

快速实现AI搜索!Fivetran 支持 Milvus 作为数据迁移目标

Fivetran 现已支持 Milvus 向量数据库作为数据迁移的目标,能够有效简化 RAG 应用和 AI 搜索中数据源接入的流程。 数据是 AI 应用的支柱,无缝连接数据是充分释放数据潜力的关键。非结构化数据对于企业搜索和检索增强生成(RAG)聊天…

深度学习500问——Chapter17:模型压缩及移动端部署(1)

文章目录 17.1 模型压缩理解 17.2 为什么需要模型压缩和加速 17.3 模型压缩的必要性及可行性 17.4 目前有哪些深度学习模型压缩方法 17.4.1 前段压缩和后端压缩对比 17.4.2 网络剪枝 17.4.3 典型剪枝方法对比 17.4.4. 网络蒸馏 17.4.5 前端压缩 17.4.6 后端压缩 深度神经网络在…

刚毕业就做项目经理,现在感觉越做越没动力,还有必要坚持下去吗?

那种一毕业就做项目经理的,以为是少走10年弯路,干了一年后,才发现这简直就是在坑自己。没点真材实料,经理也变成了“空中架子”。 因此,很多一毕业就当上项目经理的人,要么是干着干着就转回到技术岗位&…

AI数字人:终于知道视频号咋爆的了

点击下方👇“拂晓AI数字人”关注公众号 一起学习AI 数字人,让服务更高效! 做视频号是不是有这种感觉,辛辛苦苦剪了几个小时的视频,上去就是几百播放量,就没有流量了,很抓狂。 找别人的爆的视频&…

2.点位管理——帝可得后台管理系统

目录 前言点位管理菜单模块1.需求说明2.库表设计3.生成基础代码0 .使用若依代码生成器最终目标1.创建点位管理2.添加数据字典3.配置代码生成信息4.下载代码并导入项目 4.优化菜单——点位管理1.优化区域管理2.增加点位数 前言 提示:本篇介绍点位管理模块&#xff0…

知识库管理系统盘点:2024年必备10款

在当今信息爆炸的时代,高效地组织、存储、管理和共享知识与信息,已成为企业提升竞争力和实现数字化转型的关键。知识库管理系统(Knowledge Base Management System, KBMS)作为重要工具,正受到越来越多企业的青睐。本文…

使用bat命令在没有java的环境下启动jar包

使用bat命令在没有java的环境下启动jar包 先看一下目录下面的文件 里面有三个比较重要的文件 clean.bat:用于清除占用程序的端口 一键启动_x64.bat:用于启动全部的项目 jre8_win64:用于jar所需要的java环境 注意事项: 关于jar…

【RabbitMq源码阅读】分析RabbitMq发送消息源码

一&#xff1a;基本介绍 本文通过demo构建测试代码&#xff0c;debug分析的方法查看RabbitMq源码。 rabbit的中文文档&#xff1a; 官方中文文档 二&#xff1a;测试Demo 2.1 引入Springboot整合的RabbitMq依赖 <dependency><groupId>org.springframework.boot…

使用npm link 把一个本地项目变成依赖,引入到另一个项目中

突然有天,发现线上的项目有块功能缺失,我以为是我优化的时候不小心改坏了什么代码,导致的,先上图 第一反应,就以为天塌了,完全无从入手,然后我就找了之前的离职的同事,他又给我两个包,让我打成依赖扔进去,这两个包分别是scratch-blocks,scratch-vm, 然后我就使用了npm link np…

淘宝api上货软件)一刻工具箱,一天上几万不出现爬虫违规,更新开放类目错放功能,淘宝电商必备软件!

天猫淘宝抖音上货神器&#xff0c;助力电商快速铺货 在当今这个信息爆炸、电商飞速发展的时代&#xff0c;如何快速有效地将产品铺货到各大电商平台&#xff0c;成为每一位电商从业者都需要面对的问题。 通过电商API接口能为电商从业者打造的综合辅助工具&#xff0c;支持天猫、…