C++--移动构造函数/移动赋值运算符

news/2025/1/20 22:02:38/文章来源:https://www.cnblogs.com/Mr-DC/p/18238771

C++--移动构造函数/移动赋值运算符

什么是移动语义?

在C++11中,移动语义是一个重要的新特性,它可以使程序在内存管理方面更加高效,同时也提高了程序的性能

它允许将一个对象的所有权从一个对象转移到另一个对象,而不需要进行数据的拷贝。

通俗理解

我有一份材料,A同学找我借,那我把材料复印一份,把复印件给他,这叫做数据拷贝;而我如果把材料的所有权转让给他,那么他现在直接拥有原始的那份材料,这叫做移动语义。

为什么需要移动语义?

拷贝

要理解为什么我们需要移动语义,那我们就需要理解拷贝的操作

C++中有拷贝构造函数和拷贝复制运算符。拷贝,顾名思义就是重新申请一块新的内存空间,然后将需要的数据复制一份放到里面。

如果要复制的对象中涉及到了其他对象或者是指针数据的话,那么拷贝操作就是一项耗时的过程。

我们通过一个例子来演示一下是如果进行拷贝的:

定义一个简单的类:

class Myclass
{public:Myclass(const std::string& s):str(s){};private:std::string str;
};

当新建一个对象A时,传递一个参数”hello,world”,A中的成员变量会存储该字符串,也就是会申请一个新的内存空间去存储该字符串:

	Myclass A("hello,world");

当我们定义一个新的对象B,并将A赋值给B时:

	Myclass B=A;

同样,B也会申请一段空间,并将A中存储的字符串拷贝过来

需要移动语义的情况

从拷贝的操作不难看出,这样的操作是耗时的,那在什么情况下,拷贝操作不是必要的呢?

同样还是延续上面的例子,这里我们定义一个容器以及一个对象tmp,然后将其装入到容器中:

std::vector<Myclass> myClasses;
Myclass tmp("hello");
myClasses.push_back(tmp);
myClasses.push_back(tmp);

每次将对象添加到容器中都会发生一次拷贝操作。

我们现在假设tmp对象在被添加到容器中两次之后就不再需要了,那第二次添加的时候是不是可以让容器直接取tmp对象的数据呢?这就是移动语义的意义,减少不必要的数据拷贝,提高程序的性能。

假设Myclass类已经实现了移动语义,我们就可以使用std::move 让myClasses容器直接转移tmp对象的数据为己用。

myClasses.push_back(tmp);
myClasses.push_back(std::move(tmp));

移动语义的实现

我们需要先了解右值引用

右值引用

我们都知道C++有一个操作叫引用,实际上默认指的是左值引用,也就是对一个左值进行引用。那右值引用就是对右值的引用

通过&& 声明,同时:

  1. 右值引用只能绑定到一个右值,不能绑定到左值;
  2. 右值引用可以通过std::move() 将一个左值转换成右值引用
int a=0;
int&& tmp=a;   //error,不能引用左值
int&& tmp2=0;  //correct

移动构造函数

还是接着上面的例子,当向容器添加一个新元素时,如果是通过拷贝的方法,那么对应执行的就是拷贝构造函数,而如果是通过移动的方式,那对应的就是移动构造函数

下面我们就为Myclass定义移动构造函数,其中string类型本身就实现了移动构造函数,所以可以直接使用std::move

Myclass(Myclass&& rValue) noexcept:str(std::move(rValue.str)){}

在移动构造函数中,我们要做的就是转移成员数据str。

我们就可以使用移动构造函数去创建新的对象而无需拷贝复制了:

Myclass tmp("hello");
Myclass A(std::move(tmp));

如果我们的类成员数据需要我们自己实现数据转移的话,也很简单,就是把数据拿过来,并将原先对象的数据清楚:

假设这个类有两个成员变量int 和 char*类型:

class Myclass2
{
private:int data;char* str;
public:Myclass2():data(30){str="mrdc";};Myclass2(Myclass2&& rValue) noexcept:data(std::move(rValue.data)){rValue.data=0;  //delete datastr=rValue.str; //transferrValue.str=nullptr; //delete str}~Myclass2(){if(str!=nullptr){delete str;str=nullptr;}};
};

通过移动构造函数创建对象B:

MyClass A{};
MyClass B{ std::move(A) }

内存中的布局:
内存布局

移动赋值运算符

和移动构造函数的实现类似:

// 移动赋值运算符
MyClass& operator=(MyClass&& myClass) noexcept
{val = myClass.val;myClass.val = 0;name = myClass.name;myClass.name = nullptr;return *this;
}

参考

https://bbs.huaweicloud.com/blogs/375866

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

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

相关文章

java小记

今天学了一些计算机存储数据的原理: 文本,图片,声音等存储 编码:gb2312,Unicode,gbk等等。 数据类型相关遇到了一些问题:解决办法大概是:但是对于我来说是无效的,最后还是照着下面来:成功

第二次pta大作业的总结和反思

第二次pta大作业的总结和反思 目录 一.前言 二.题目分析 三.总结 一.前言 第二次作业说实话有点一言难尽啊,因为比较难的缘故吧,有的题甚至做了一个星期也没做完,所以blog有点无从下手,因为有很多题目是现想的,没有经过调试,不知道思路究竟对不对,可能会有一些理解上会些…

1_关于BeanFactory与ApplicationContext的联系和区别

BeanFactory与ApplicationContext 1. 容器和接口 1.1 BeanFactory与ApplicationContext的联系与区别: ConfigurableApplicationContext 是 ApplicationContext的子接口,而ApplicationContext接口又是 BeanFactory 的子接口。因此ConfigurableApplicationContext 接口简介继承…

回溯法求解TSP问题

1.readme 1>python 2>代码基于具体的实例,如有需要可自行修改问题规模为n,不再赘述 2.code 代价矩阵 999表示无穷 arc = [[999, 3, 6, 7], [5, 999, 2, 3], [6, 4, 999, 2], [3, 7, 5, 999]] city 存放除出发点0外的城市 city = [3, 2, 1] 访问标志数组 0-未访问 1-已访…

OpenGL:混合

OpenGL中,混合(Blending)通常是实现物体透明度(Transparency)的一种技术。透明就是说一个物体(或者其中的一部分)不是纯色(Solid Color)的,它的颜色是物体本身的颜色和它背后其它物体的颜色的不同强度结合。一个有色玻璃窗是一个透明的物体,玻璃有它自己的颜色,但它最终的…

下水道拾的沟槽的文章

wow天色将晚,在我看着你的眼里色彩斑斓 五月的气候合往年一样闷热,二中的晚自习太静,于是闲下来了,止不住地去向,好像又来一轮毕业的时候。小学时,谈起毕业总是很害怕的,那时觉得毕业时候一定是要大哭一场,不然就算不上毕业结果那天也如同流水一般平淡地过去了,正如过…

P3756 [CQOI2017] 老C的方块 解题报告

P3756 [CQOI2017] 老C的方块 解题报告oj:https://gxyzoj.com/d/gxyznoi/p/P266 又是网格题,考虑染色:显然可以发现,每一个不合法的图形都可以被染成黄->蓝->特殊边->绿->红,且旋转后同样满足条件 推广到整个棋盘就是:所以是否可以将颜色编号,然后按照上述方法…

[stars-one] 星念轻小说下载器

原文地址: [stars-one] 星念轻小说下载器-Stars-One的杂货小窝 一款将在线轻小说保存到本地的下载工具 软件介绍小说单卷下载 小说全卷下载(需VIP) 多线程解析和下载 下载导出为epub文件 自动更新软件使用前需要进行用户登录(邮箱注册) 采用会员订阅制,PC版和Android版共用账号…

裁剪序列Cut the Sequence

首先,我们可以先想一想朴素算法,推出DP,i表示分了几段,则可以推出$$F[i]=min_{1<=j<=i}(f[j]+max_{j+1<=k<=i}(a[k]))$$点击查看代码memset(f,0x3f,sizeof f);f[0]=0;for(int i=1;i<=n;i++){for(int j=0;j<i;j++){int tmp=0;ll sum=0;for(int k=j+1;k<…

vits-simple-api搭建

根据vits-simple-api中文文档指南自行搭建后端 以下步骤均在windows平台cpu推理搭建为例选择你的vits模型(注意是vits!不是So-Vits Bert Vits2 Gpt Vits)建议去抱脸网搜索或者b站搜素以及自己训练.在vits-simple-api的路径的model目录下新建你下载模型的名字的文件夹将模型的js…

bili-emoji自定义表情包设置

使用图床上传图片.推荐使用聚合图床,简单免费 把图片的图床链接复制到一个txt文件中,如abc.txt 将abc.txt放到koishi目录的非node_modules\koishi-plugin-emojihub-bili文件夹中,如koishi\lumia\abc.txt 在插件界面填写要触发的命令以及路径如下图所示5.使用如下图所示

关于LTspice如何导入第三方的.lib文件进行仿真

转载自:https://bbs.eeworld.com.cn/thread-1265324-1-1.html 1.在芯片官网找到对应的PSPICE模型下载后,将.lib文件移入到路径下的sub文件夹中。(例如C:\Users\\username\Documents\LTspiceXVII\lib\sub) 2.将.lib文件拖入LTspice后右键单击.subckt后的芯片名称,选择Creat S…