C++ 之 移动构造函数

news/2024/5/19 18:36:37/文章来源:https://blog.csdn.net/bin_bujiangjiu/article/details/128077540

1、左值和右值

C++( 包括 C) 中所有的表达式和变量要么是左值,要么是右值。

  1. 通俗的左值的定义就是非临时对象,那些可以在多条语句中使用的对象,表达式结束后依然存在的持久化对象,所有的具名变量或者对象都是左值。
  2. 右值是指临时的对象,它们只在当前的语句中有效,他就像是代表了一个由编译器创建的临时内存位置,在访问它之后,该内存就会被回收,该值也不能被访问了。

具体代码如下 :

int i = 0;           // i是左值, 0是右值,i在当前表达式结束之后,依然可以被使用,被引用,而0不行,它是临时值,当前表达式结束之后,此表达式中的0值就不存在了class A {public:int a;
};A getTemp()
{return A();
}
A a = getTemp();      // a是左值  getTemp()的返回值是右值(临时变量)((i>0) ? i : j) = 1;   //右值不只是存在在表达式的右边,在此表达式中,0作为右值出现在表达式的左边,并且将值赋值给i或者j。  const int &a = 1;     //在 C++11 之前,右值是不能被引用的,最大限度就是用常量引用绑定一个右值T().set().get();      //在这种情况下,右值是可以被修改的,T 是一个类,set 是一个函数为 T 中的一个变量赋值,get 用来取出这个变量的值。在这句中,T() 生成一个临时对象,就是右值,set() 修改了变量的值,也就修改了这个右值。

2、左值引用和右值引用

(1)左值引用就是最传统的引用 &。
如下:

int a = 10;
int& refA = a; // refA是a的别名, 修改refA就是修改a, a是左值,左移是左值引用
int& b = 1; //编译错误! 1是右值,不能够使用左值引用

(2)C++ Primer Plus 第6版18.1.9中说到,c++11中增加了右值引用,右值引用关联到右值时,右值被存储到特定位置,右值引用指向该特定位置,也就是说,右值虽然无法获取地址,但是右值引用是可以获取地址的,该地址表示临时对象的存储位置。具体语法如下:

int&& a = 1; // &&是右值引用的符号,实质上就是将不具名(匿名)变量取了个别名
int b = 1;
int && c = b; //编译错误! 不能将一个左值复制给一个右值引用

(3) 右值引用的三个特点:
a、通过右值引用的声明,右值又“重获新生”,其生命周期与右值引用类型变量的生命周期一样长,只要该变量还活着,该右值临时量将会一直存活下去。

class A {public:int a;
};
A getTemp()
{return A();
}
A && a = getTemp();   //getTemp()的返回值是右值(临时变量)getTemp()返回的右值本来在表达式语句结束后,其生命也就该终结了(因为是临时变量),//而通过右值引用,该右值又重获新生,其生命期将与右值引用类型变量a的生命期一样,只要a还活着,该右值临时变量将会一直存活下去。

b、右值引用独立于左值和右值。意思是右值引用类型的变量可能是左值也可能是右值。
从下面的代码中可以看到,T&&表示的值类型不确定,可能是左值又可能是右值,这就是右值引用的一个特点。

template<typename T>
void f(T&& t){}f(10); //t是右值int x = 10;
f(x); //t是左值

c、T&& t在发生自动类型推断的时候,它是未定的引用类型(universal references),如果被一个左值初始化,它就是一个左值;如果它被一个右值初始化,它就是一个右值,它是左值还是右值取决于它的初始化。

template<typename T>
void f(T&& t){}
f(10); //t是右值   //这里发生自动类型推断int x = 10;
f(x); //t是左值    //发生自动类型推断template<typename T>
class Test {Test(Test&& rhs); //这里不会发生类型推断,因为已经是确定的Tset &&类型的
};

3、const左值引用

从上面的例子可以看到,
左值引用只能绑定左值,右值引用只能绑定右值,如果绑定的不对,编译就会失败。但是,const左值引用却是个奇葩,它可以算是一个“万能”的引用类型,它可以绑定非常量左值、常量左值、右值,而且在绑定右值的时候,常量左值引用还可以像右值引用一样将右值的生命期延长,缺点是,只能读不能改。

const int & a = 1; //常量左值引用绑定 右值, 不会报错class A {public:int a;
};
A getTemp()
{return A();
}
const A & a = getTemp();   //不会报错 而 A& a 会报错

总结如下(其中T是一个类型):
左值引用, 使用 T&, 只能绑定左值
右值引用, 使用 T&&, 只能绑定右值
常量左值, 使用 const T&, 既可以绑定左值又可以绑定右值
已命名的右值引用,编译器会认为是个左值

4、移动构造函数和移动赋值函数

首先,移动构造函数是一个构造函数,他是用来构造一个对象的,和拷贝构造函数、构造函数等价。但与默认构造函数不同,编译器不提供默认移动构造函数。移动构造函数和移动赋值函数所执行的是同样的操作,只不过情况不一样,一种是直接构造一个对象,另一种是利用“=”运算符把一个对象赋值给另一个对象的时候。
移动构造函数和移动赋值函数与拷贝构造函数所执行的作用的是一样的,都是通过一个对象去构造一个新对象。但有时候我们会遇到这样一种情况,我们用对象a初始化对象b,后对象a我们就不在使用了,但是对象a掌握的内存资源仍然存在(在析构之前),既然拷贝构造函数,实际上就是把a对象的内容复制一份到b中,那么为什么我们不能直接使用a对象掌握的内存空间?这样就避免了新的空间的分配,大大降低了构造的成本。这就是移动构造函数设计的初衷。
总的来说,就是类中有指针类型的成员变量时,当遇到对象构造对象时,需要使用拷贝构造函数中的深拷贝的方式把该指针成员赋值,这种深拷贝的方法会重新在堆上分配成员指针分配内存,当出现多次上述对象a初始化对象b之后,对象a不在存在的情况是,程序就会在堆上分配多次内存,大大降低程序运行效率,所以移动构造函数就将即将放弃的对象的内存空间直接给新对象使用,就能避免许多临时对象的创建,也能避免程序多次在堆上申请空间,从而大大的提高了执行效率。他的原型如下:

 A & operator=(A &&); //右值引用//正确的移动构造函数的写法A(A && a):p(a.p){std::cout<<"move c"<<std::endl;//如果调用A的移动构造函数,则打印 "move c"a.p=nullptr;     //移动构造函数的灵魂在与使临时对象的指针为空,从而占据临时对象的内存空间,在临时对象析构的时候也不会造成指针悬挂。}//正确的移动赋值函数写法A & operator=(A && a){if(&a == this)return *this;p=a.p;a.p=nullptr;return *this;}

对于移动构造函数,需要以下几点需要注意:
参数(右值)的符号必须是右值引用符号,即“&&”,因为右值是即将析构的对象,将它的内存空间变废为用,可以提高效率。
参数(右值)不可以是常量,因为我们需要修改右值。
参数(右值)的资源链接和标记必须修改。否则,右值的析构函数就会释放资源。转移到新对象的资源也就无效了。
移动构造函数的原理如下图:
在这里插入图片描述

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

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

相关文章

设置渐变边框色

如上图所示&#xff0c;需设置渐变边框色&#xff0c;左右边框颜色固定&#xff0c;上边框从左到右开始渐变&#xff0c;下边框从右到左开始渐变。 思考了很久&#xff0c;如果看作是一个div&#xff0c;则需要用到 border-image属性设置渐变色。也可以看作是两个div&#xff0…

CISAW信息安全保障人员认证考试难吗?

CISAW信息安全保障人员认证&#xff0c;作为信息安全行业相当热门的证书之一&#xff0c;其持证人数已超50%&#xff0c;在信息安全行业内占有一席之地&#xff0c;很多报考人都比较关心CISAW考试难不难&#xff1f;能通过吗&#xff1f;那接下来说一说CISAW证书考不好考&#…

常见的网络协议

目录 一、TCP/IP协议簇 二、网络设备与五层模型对应关系&#xff1a; 三、常用网络协议总结&#xff08;TCP/IP协议簇&#xff09; 四、应用层服务协议 五、传输层协议组 TCP_UDP 六、网络层协议 IP_ICMP_ARP 七、物理层协议 MAC子层协议 一、TCP/IP协议簇 OSI七层模型…

IBM MQ 故障诊断(一)

说明&#xff1a;本文主要是针对运维人员的手册。前面部分主要是应用三板斧的方式&#xff0c;后面的步骤可能会发散和具体深入一些。不过也不是严格的划分&#xff0c;读者就当看一遍杂文的方式来看待此文吧。 一&#xff0c;队列管理器的启停 QMGR的启停是故障诊断中遇到最…

[附源码]SSM计算机毕业设计线上图书销售管理系统JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

用huggingface.transformers在文本分类任务(单任务和多任务场景下)上微调预训练模型

诸神缄默不语-个人CSDN博文目录 transformers官方文档&#xff1a;https://huggingface.co/docs/transformers/index AutoModel文档&#xff1a;https://huggingface.co/docs/transformers/v4.23.1/en/model_doc/auto#transformers.AutoModel AutoTokenizer文档&#xff1a;ht…

Java#数据结构----2

目录 一.数据结构(树) 二.二叉树(任意节点的度<2) 二叉查找树又称为二叉排序树/二叉搜索树 平衡二叉树 平衡二叉树的旋转机制 三.红黑树 一.数据结构(树) 基本概念: 度: 每一个节点的子节点数量 树高: 树的总层数 根节点: 最顶层的节点 左子节点: 左下方的节点 右子节…

优维低代码:Redirect 路由重定向If 条件渲染

优维低代码技术专栏&#xff0c;是一个全新的、技术为主的专栏&#xff0c;由优维技术委员会成员执笔&#xff0c;基于优维7年低代码技术研发及运维成果&#xff0c;主要介绍低代码相关的技术原理及架构逻辑&#xff0c;目的是给广大运维人提供一个技术交流与学习的平台。 连载…

2022年超实用的推特营销策略

Twitter推广需知的13条基础知识&#xff1a; 1、Twitter日活用户达1亿 2、Twitter月活用户3.25亿 3、Twitter广告价格比其他渠道便宜33% 4、每天产生5亿条推文 5、Twitter推广能够提高29%的线下交易 6、37%的Twitter用户在18到29岁之间 7、86%的带链接推文会比普通推文效…

Cerebral Cortex:调节γ振荡可以促进大脑连接性而改善认知障碍

摘要 老年痴呆症造成了巨大的全球经济负担&#xff0c;但目前还缺乏有效的治疗方法。最近的研究表明&#xff0c;脑电活动的伽马波段波&#xff0c;特别是40赫兹振荡&#xff0c;与高阶认知功能密切相关&#xff0c;可以激活小胶质细胞清除淀粉样蛋白&#xff0d;β沉积。本研究…

Flowable 中的网关、流程变量以及历史流程

今天这篇文章&#xff0c;松哥和大家梳理一下 Flowable 中的网关、流程变量以及历史流程的玩法。 1. 三大网关 Flowable 中网关类型其实也不少&#xff0c;常见的主要有三种类型&#xff0c;分别是&#xff1a; 排他网关并行网关包容网关 这三个里边最常用的当然就是排他网关…

Cesium中的DataSource和Entity关系

本章主要探讨一下Cesium中的DataSource和Entity。 介绍 首先简单说一下Entity与Primitive。 Cesium为开发者提供了丰富的图形绘制和空间数据管理的API&#xff0c;可以分为两类&#xff0c;一类是面向图形开发人员的低层次API&#xff0c;通常被称为Primitive API&#xff0…

连续时间系统的时域分析

一.微分方程的求解 1.求微分方程的齐次解 &#xff08;1&#xff09;写出特征方程并求解 2.写出齐次解 2.求微分方程的特解 已知 &#xff08;1&#xff09;根据表2-2&#xff0c;写出特解函数 ​​​​​​​ &#xff08;2&#xff09;带入并求解 3.完全解 二.微分方…

小杨哥陷入打假风波,会变成下一个辛巴吗?

最近&#xff0c;网红疯狂小杨哥频繁登上热搜。最初的起因是他花了1亿元在合肥一家高科技公司购买了5万多平方米的房产&#xff0c;作为他名下公司的全球总部&#xff0c;由此带来了争议。 据了解&#xff0c;该物业总建筑面积为53874.33平方米&#xff0c;包括1个生产综合体、…

使用扩展有效对齐 SwiftUI 内容,创建自定义 SwiftUI 方法以快速对齐项目并使您的代码看起来简洁明了(教程含源码)

在开发 iOS 应用程序时,对齐内容可能是一个耗时的过程。如果应用程序有多个屏幕,则需要在不同的地方完成这件事,并可能导致看起来杂乱无章的视图。 作为一个始终致力于让我的代码看起来简单和流线型的人,实现目标所需的大量Spacer()元素常常让我恼火,这就是为什么当我发…

APS软件的技术指标与特色

企业可能经常会因为无法掌握生产制造现场的实际产能状况及物料进货状况&#xff0c;导致物料及产能规划与现场详细作业排程难度增大&#xff0c;从而采取有单就接的接单政策与粗估产能的生产排程方式。这种方式就可能导致企业的生产状况频发&#xff1a;在提高对顾客的服务水平…

【树莓派不吃灰】Linux篇⑨ 学习 磁碟配额(Quota)与进阶文件系统管理(核心概念)

目录1. 磁碟配额 (Quota) 的应用与实作2.软件磁盘阵列 (Software RAID)3. 逻辑卷轴管理员 (Logical Volume Manager)4. 重点回顾❤️ 博客主页 单片机菜鸟哥&#xff0c;一个野生非专业硬件IOT爱好者 ❤️❤️ 本篇创建记录 2022-11-28 ❤️❤️ 本篇更新记录 2022-11-28 ❤️&…

如何采集需要验证码登录的网站数据

如何抓取网页上的数据,需要登录&#xff1f;随着互联网的发展&#xff0c;移动支付技术的普及&#xff0c;以及人们对内容进行消费的观念逐渐养成。有很多网站&#xff0c;需要付费后才能查看&#xff0c;或者是开通会员之类的才能查看。针对这类网站&#xff0c;我们如何快速的…

Scrapy基本概念——Scrapy shell

Scrapy shell是一个交互式shell&#xff0c;可以在不运行Spider的情况下&#xff0c;测试和调试自己的数据提取代码。事实上&#xff0c;Scrapy shell可以测试任何类型的代码&#xff0c;因为它本就是一个常规的Python shell。 一、Scrapy shell的使用 1、启动Scrapy shell …

动态规划算法(1)

认识动态规划 动态规划的求解思路&#xff1a; 1. 把一个问题分解成若干个子问题 2. 将中间结果保存以避免重复计算 基本步骤&#xff1a; 1. 找出最优解的性质&#xff0c;然后刻画结构特征 &#xff08;找规律&#xff09; 2. 最优解(最好的解决方案 定义) 循环(递归) 3. 以…