当前位置: 首页 > news >正文

28 C++ 对象移动,移动构造函数,移动赋值运算符

前提回顾:

我们之前学过了类内部的初始化构造函数有如下几种

构造函数

拷贝构造函数

赋值运算符拷贝构造函数

今天还是学习一个 移动构造函数

我先将前面学习的三种构造函数的写法以及运用场景整理如下:

构造方法,copy构造函数,等号赋值运算符 构造函数
//构造函数,拷贝构造函数,赋值运算符拷贝构造函数 总结整理
class Teacher77 {public:Teacher77() {}//构造函数Teacher77(int age/*in*/,char *name/*in*/,string address/*in*/,char *title/*in*/,char ** studentname/*in*/,string * familyname):m_age(age),m_address(address){//char m_name[64]需要copystrcpy_s(this->m_name,sizeof(this->m_name),name);//title是 char *this->m_title = title;//studentname 是char **this->m_studentname = studentname;this->m_familyname = familyname;cout << "构造函数被调用" << endl;}// copy 构造函数被调用Teacher77  (const Teacher77 & obj):m_age(obj.m_age),m_address(obj.m_address),m_title(obj.m_title),m_studentname(obj.m_studentname),m_familyname(obj.m_familyname){//char m_name[64]需要copystrcpy_s(this->m_name, sizeof(this->m_name), obj.m_name);cout << "copy 构造函数被调用" << endl;}// 赋值等号运算符 被调用Teacher77& operator=(Teacher77& obj){this->m_age = obj.m_age;strcpy_s(this->m_name, sizeof(this->m_name), obj.m_name);this->m_address = obj.m_address;this->m_title = obj.m_title;this->m_familyname = obj.m_familyname;this->m_studentname = obj.m_studentname;cout << "等号赋值运算符构造函数被调用" << endl;return *this;}private:int m_age; //年龄char m_name[64] = { 0 };//名字string m_address;//家庭住址char *m_title; // 职称,char **m_studentname;//学生名字,我们目前 认为一个老师只带了三个学生string *m_familyname;//家人信息public:void printTeacher() {cout << "  m_age = " << this->m_age << endl;cout << "  m_name = " << this->m_name << endl;cout << "  m_address = " << this->m_address << endl;cout << "  m_title = " << this->m_title << endl;int i = 0;while (this->m_studentname[i] !=nullptr){cout << "  m_studentname[" << i << "] = " << this->m_studentname[i];i++;}cout << endl;int j = 0;while (!this->m_familyname[j].empty()){cout << "  m_familyname[" << j << "] = " << this->m_familyname[j];j++;}cout << endl;}void setTitle(char * newtitle) {this->m_title = newtitle;}
};void main() {//第一种构造方法,全部元素都是在 栈 中 弄出来int age = 28;char name[64] = "teachername";string address("teacheraddress");char *title = (char *)"teachertitle";char *studentname[4] = { (char *)"student111" ,(char *)"student222" ,(char *)"student333",nullptr };//最后一个值写成nullptr,是为了在读取的时候,判断最后一位,在C++中,这叫做岗哨string familyname[6] = { "baba","mama","son","nver","sunzi","" };//最后一个值写成"",是为了在读取的时候,判断最后一位,在C++中,这叫做岗哨.岗哨不一定是nullptr,也不一定是"",根据实际类型和您的业务逻辑来判断写成什么,只是nullptr ,null,""这些比较常用Teacher77 tea(age,name,address,title,studentname, familyname);tea.printTeacher();cout << "-------" << endl;//第一种 copy 构造方法Teacher77 tea2 = tea;tea2.printTeacher();cout << "-------" << endl;tea2.setTitle((char *)"newtitle");tea2.printTeacher();cout << "-------" << endl;tea.printTeacher();cout << "-------" << endl;//第一种 等号运算符重载 构造方法被调用Teacher77 tea3;tea3 = tea2;tea3.printTeacher();
}

移动构造函数 学习

C++ 11中引入。

使用场景

将对象a 中的数据 转让给 对象b,这部分数据主要是指针。

那么对象a中的数据就不能再次使用了。

需要考虑到a在析构时的问题,如果已经将a给b 了,那么a中的指针如果和b同时 delete,就会有问题。

因此在 移动构造函数中让切断a对象的指针指向,也就是让对象a中的指针要指向nullpotr

如可能,请尽量的给类中添加 移动构造 和移动赋值

如果没有手动的写移动构造函数,那么C++编译器会调用 拷贝函数代替。

移动构造函数 最好后面加上 noexcept,这样的含义是:告知C++ 我不会抛出异常

移动构造函数的写法:


//移动构造函数class Teacher79 {
public:Teacher79() {cout << "Teacher79的 构造函数 被调用" << endl;}~Teacher79() {cout << "Teacher79的 析构函数 被调用" << endl;}Teacher79(const Teacher79 &obj) {cout << "Teacher79的 copy 构造函数被调用" << endl;}Teacher79& operator= (const Teacher79& obj) {cout << "Teacher79的 = 运算符 被调用" << endl;return *this;}Teacher79(Teacher79 &&obj) {cout << "Teacher79的 移动构造函数  被调用" << endl;}
};class Teacher80 {
public:Teacher80() :pt79(new Teacher79()) {cout << "Teacher80的构造函数被调用" << endl;}~Teacher80() {if (pt79 != nullptr) {delete pt79;pt79 = nullptr;cout << "delete pt79" << endl;}cout << "Teacher80的析构函数被调用" << endl;}Teacher80(const Teacher80 &obj):pt79(new Teacher79(*(obj.pt79))) {cout << "Teacher80的 copy 构造函数被调用" << endl;}Teacher80(Teacher80 &&obj) noexcept {cout << "Teacher80的 移动构造函数  被调用" << endl;this->pt79 = obj.pt79;obj.pt79 = nullptr;}Teacher80& operator= (const Teacher80& obj) {cout << "Teacher80的 = 运算符 被调用" << endl;return *this;}private:Teacher79 *pt79;public:};static Teacher80 getTeacher80() {Teacher80 tempt80;return tempt80;//Teacher79的 构造函数 被调用  tempt80的构造//	Teacher80的构造函数被调用  tempt80的构造//	Teacher80的 移动构造函数  将tempt80 通过移动构造传递给了一个看不见的临时对象,//	Teacher80的析构函数被调用  tempt80的析构 由于tempt80指向了移动构造函数,pt79已经被置为nullptr了,因此这里tempt80的析构,没有打印析构pt79//	Teacher79的 析构函数 被调用 //由于临时对象并没有人接,因此立即也执行了析构函数,临时对象是有pt79的,因此会打印析构pt79的log//	delete pt79//	Teacher80的析构函数被调用
}void main() {getTeacher80();cout << "duandian2" << endl;
}

对比 copy 构造函数和 移动构造函数

	//copy 构造函数Teacher80(const Teacher80 &obj):pt79(new Teacher79(*(obj.pt79))) {cout << "Teacher80的 copy 构造函数被调用" << endl;}//copy 构造函数 和 上面那个一样,因此只能写一个,这里写两个是练手,上一个写法包含了初始化函数参数列表的行为。Teacher80(const Teacher80 &obj) {cout << "Teacher80的 copy 构造函数被调用" << endl;this->pt79 = new Teacher79(*(obj.pt79));}//移动 构造函数Teacher80(Teacher80 &&obj) noexcept {cout << "Teacher80的 移动构造函数  被调用" << endl;this->pt79 = obj.pt79;obj.pt79 = nullptr;}

移动赋值运算符的写法

	Teacher80& operator= ( Teacher80&& obj) {cout << "Teacher80的 移动赋值 运算符 被调用" << endl;if (this == &obj) {return *this;}//先把自己的内存干掉delete this->pt79;this->pt79 = obj.pt79;//再将obj 的pt79 拿过来用obj.pt79 = nullptr; // 最后斩断obj的指针指向return *this;}调用Teacher80 t1;Teacher80 t2;t2 = move(t1);//由于 Teacher80手动的重写了 移动赋值运算符,就会走 移动赋值运算符函数;如果没有写,会走 =号的函数

相关文章:

  • 关于axios的二次封装
  • Kafka安全认证机制详解之SASL_PLAIN
  • Vue2/Vue3-插槽(全)
  • C++ KMP字符串 ||暴力算法 和 KMP算法模板题解法
  • 作业三详解
  • STM32 ESP8266 物联网智能温室大棚 (附源码 PCB 原理图 设计文档)
  • MR实战:词频统计
  • git本地创建分支并推送到远程关联起来
  • LLM之RAG实战(十三)| 利用MongoDB矢量搜索实现RAG高级检索
  • 【Unity嵌入Android原生工程】
  • java基础之Java8新特性-Stream(流)
  • 弹窗里el-cascader下拉框脱离文档流的解决办法
  • BLE Mesh蓝牙组网技术详细解析之Model Layer模型层(八)
  • MySQL-数据库概述
  • HTML----JavaScript操作对象BOM对象
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  • angular组件开发
  • classpath对获取配置文件的影响
  • docker-consul
  • E-HPC支持多队列管理和自动伸缩
  • hadoop入门学习教程--DKHadoop完整安装步骤
  • Javascript编码规范
  • Next.js之基础概念(二)
  • Spring核心 Bean的高级装配
  • 动态规划入门(以爬楼梯为例)
  • 关于使用markdown的方法(引自CSDN教程)
  • 聊聊spring cloud的LoadBalancerAutoConfiguration
  • 七牛云假注销小指南
  • 一个JAVA程序员成长之路分享
  • 怎么把视频里的音乐提取出来
  • Oracle Portal 11g Diagnostics using Remote Diagnostic Agent (RDA) [ID 1059805.
  • SAP CRM里Lead通过工作流自动创建Opportunity的原理讲解 ...
  • 哈罗单车融资几十亿元,蚂蚁金服与春华资本加持 ...
  • #100天计划# 2013年9月29日
  • #我与Java虚拟机的故事#连载11: JVM学习之路
  • (1)Nginx简介和安装教程
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (初研) Sentence-embedding fine-tune notebook
  • (附源码)springboot猪场管理系统 毕业设计 160901
  • (附源码)小程序 交通违法举报系统 毕业设计 242045
  • (六)vue-router+UI组件库
  • (一)VirtualBox安装增强功能
  • .NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划
  • .net refrector
  • .Net Web项目创建比较不错的参考文章
  • .NET 将混合了多个不同平台(Windows Mac Linux)的文件 目录的路径格式化成同一个平台下的路径
  • .NET 中的轻量级线程安全
  • /usr/bin/python: can't decompress data; zlib not available 的异常处理
  • @AliasFor注解
  • @ComponentScan比较
  • @RequestParam @RequestBody @PathVariable 等参数绑定注解详解
  • [100天算法】-每个元音包含偶数次的最长子字符串(day 53)
  • [1525]字符统计2 (哈希)SDUT
  • [20181219]script使用小技巧.txt
  • [3300万人的聊天室] 作为产品的上游公司该如何?