有指针或者多维数组时,如何写 拷贝构造函数,移动构造函数,拷贝赋值运算符,移动赋值运算符

news2024/12/23 9:53:48

当成员变量里面有指针或者多维数组时,如何写 拷贝构造函数,移动构造函数,拷贝赋值运算符,移动赋值运算符

头文件

#pragma once
#include<iostream>
using namespace std;
const int num = 5;
/*
重写C++默认函数
*/
class DefaultRewrite
{
public:
	DefaultRewrite();
	// 拷贝构造函数
	DefaultRewrite(const DefaultRewrite& other);
	// 手动定义拷贝赋值运算符
	DefaultRewrite& operator=(const DefaultRewrite& other);
	// 移动构造函数
	DefaultRewrite(DefaultRewrite&& other);
	// 自定义移动赋值运算符
	DefaultRewrite& operator=(DefaultRewrite&& other);
	void initBuffer(char* copy,int size);
	void printDefaultRewrite();
private:

	char* m_pBuf;
	int cal[num][num];
	int m_bufSize;
};


实现

#include "DefaultRewrite.h"


DefaultRewrite::DefaultRewrite():
	m_pBuf(nullptr), cal{}, m_bufSize(num)
{
	cout << "默认构造函数" << endl;
}

DefaultRewrite::~DefaultRewrite()
{
	if (m_pBuf  )
	{
		delete[] m_pBuf;
	}
	m_pBuf = nullptr;
	cout << "析构函数" << endl;
}
void DefaultRewrite::initBuffer(char* copy, int size)
{
	int minsize = min(size, m_bufSize);
	if (m_pBuf == nullptr)
	{
		m_pBuf = new char[m_bufSize];
	}
	//std::copy(copy, copy + minsize, m_pBuf);
	memcpy(m_pBuf, copy, m_bufSize);
	for (int i = 0; i < num; i++) 
	{
		for (int j = 0; j < num; j++) 
		{
			cal[i][j] = i+j;
		}
	}
}

// 拷贝构造函数
DefaultRewrite::DefaultRewrite(const DefaultRewrite& other)
	: m_pBuf(other.m_pBuf) , m_bufSize(other.m_bufSize)
{
	cout << "拷贝构造函数" << endl;
	std::copy(&other.cal[0][0], &other.cal[0][0] + num * num, &cal[0][0]);
	if (other.m_pBuf)
	{
		m_pBuf = new char[m_bufSize];

		//std::copy(other.m_pBuf, other.m_pBuf + m_bufSize, m_pBuf);
		memcpy(m_pBuf, other.m_pBuf, m_bufSize);
	}
	else
	{
		m_pBuf = nullptr;
	}

}

// 拷贝赋值运算符
DefaultRewrite& DefaultRewrite::operator=(const DefaultRewrite& other) {
	cout << "拷贝赋值运算符" << endl;
	
	if (this == &other) return *this;

	if (m_pBuf)
	{
		delete[] m_pBuf;
	}
	// 深拷贝
	m_pBuf = new char[m_bufSize];
	std::copy(&other.cal[0][0], &other.cal[0][0] + num * num, &cal[0][0]);
	//std::copy(other.m_pBuf, other.m_pBuf + m_bufSize, m_pBuf);
	memcpy(m_pBuf, other.m_pBuf, m_bufSize);
	return *this;
}

// 移动构造函数
DefaultRewrite::DefaultRewrite(DefaultRewrite&& other) 
	: m_pBuf(other.m_pBuf), m_bufSize(other.m_bufSize)
{
	
	cout << "移动构造函数" << endl;
	other.m_pBuf = nullptr;
	std::copy(&other.cal[0][0], &other.cal[0][0] + num * num, &cal[0][0]);
}

// 移动赋值运算符
DefaultRewrite& DefaultRewrite::operator=(DefaultRewrite&& other) 
{
	
	cout << "移动赋值运算符" << endl;
	if (this == &other) return *this;

	if (m_pBuf)
	{
		delete[] m_pBuf;
	}

	m_pBuf = other.m_pBuf;
	m_bufSize = other.m_bufSize;
	std::copy(&other.cal[0][0], &other.cal[0][0] + num * num, &cal[0][0]);

	other.m_pBuf = nullptr;

	return *this;
}

void DefaultRewrite::printDefaultRewrite()
{
	if(m_pBuf)
	cout << m_pBuf << endl;
	for (int i = 0; i < num; i++)
	{
		for (int j = 0; j < num; j++)
		{
			cout << cal[i][j] << "  ";
		}
		cout << endl;
	}
}

main

int main()
{	DefaultRewrite obj1; // 默认构造函数
	cout << "obj1" << endl;
	obj1.printDefaultRewrite();

	char str[] = "hi";
	obj1.initBuffer(str,3);
	cout << "obj1 initBuffer" << endl;
	obj1.printDefaultRewrite();

	DefaultRewrite obj2 = obj1; // 拷贝构造函数
	cout << "obj2" << endl;
	obj2.printDefaultRewrite();
	

	DefaultRewrite obj3;
	obj3 = obj1; // 拷贝赋值运算符
	cout << "obj3" << endl;
	obj3.printDefaultRewrite();

	DefaultRewrite obj4(std::move(obj2)); // 移动构造函数
	cout << "obj4" << endl;
	obj4.printDefaultRewrite();

	DefaultRewrite obj5;
	obj5 = std::move(obj1); // 移动赋值运算符
	cout << "obj5" << endl;
	obj5.printDefaultRewrite();


	cout << "obj1" << endl;
	obj1.printDefaultRewrite();

	cout << "obj2" << endl;
	obj2.printDefaultRewrite();
}

运行结果
在这里插入图片描述

注意事项

move

在代码中调用obj3 = std::move(obj1)后,obj1之所以还可以继续被使用,主要原因是:

移动语义的转移是通过“窃取”资源的方式实现的。

  1. std::move(obj1)只是将obj1转换为一个右值,本身不会做实际的资源转移。

  2. 随后调用DefaultRewrite的移动赋值运算符实现资源的转移。

  3. 但移动赋值运算符只将obj1的m_pBuf指针转移给了obj3。

  4. obj1的其他成员如m_bufSize等并没有被修改。

  5. 所以obj1的成员中只有m_pBuf被置为空指针,其他成员依然保持有效状态。

  6. 这就是移动语义的“destructive move” 特性,移动后源对象可处于任意状态。

  7. 如果obj1的其他成员没有再次使用m_pBuf,那么obj1仍可继续正常使用。

  8. 但需要注意,obj1的m_pBuf已经失效,不能再被访问。

总结来说,移动语义下源对象可被部分重用,这 depends on 的是资源的转移方式。如果只转移部分资源,源对象可能依然可以使用剩余的资源。

数组初始化与赋值

cal=other.cal;为什么会报错
数组名是一个地址常量,其值和第一个元素的地址值相同,不可修改。赋值号左边必须是一个变量
https://blog.csdn.net/huang1600301017/article/details/88562653

深拷贝

数组和指针在这四个函数里面都需要手动深拷贝

在移动构造函数中,对指针成员m_pBuf我们直接进行了浅拷贝:

m_pBuf = other.m_pBuf; 

移动语义

没有进行深拷贝, 是可以的。主要原因有:

  1. 移动构造的目的是资源的转移,而不是共享。

  2. 我们期望移动操作后,源对象不再使用这部分资源。

  3. 直接使两个对象的指针指向同一区域,即实现了资源的转移。

  4. 如果我们深拷贝,就会造成资源冗余,降低效率。

  5. 移动后源对象的指针会被置空,不会再访问这个区域。

  6. 所以这种“浅拷贝”方式实现了零开销的资源转移。

  7. 这也是移动语义的设计目的,比深拷贝更高效。

当然,如果指针指向的内容还会被源对象使用,我们就不能这样直接转移指针。

但在移动语义下,通常假设源对象资源不再被使用,所以直接指针赋值即可优化。

这是移动构造可以进行资源“窃取”的原理所在。

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

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

相关文章

低代码赋能| 你真的了解物联网操作系统嘛?点进来看干货!

在聊物联网操作系统之前&#xff0c;我们先来聊物联网。 什么是物联网&#xff1f;物联网&#xff08;IoT&#xff09;是实现万物互联的技术&#xff0c;它赋予物品以控制力、感知力和决策力&#xff0c;推动各类生活场景向智能化方向发展。从架构的层面来说&#xff0c;物联网…

技术科普:汽车开放系统架构AUTOSAR

01.AUTOSAR简介 汽车是现代人类实现“千里江陵一日还”的交通工具&#xff0c;而计算机则是使人脱离繁杂重复脑力劳动的生产技术&#xff0c;两者的结合催生了汽车电子产业的蓬勃发展。 21世纪初&#xff0c;随着汽车电子应用需求的不断增多与硬件资源不断丰富&#xff0c;软…

大数据时代下的精准营销

在大数据时代&#xff0c;人们的信息越来越透明&#xff0c;留在网络上的各种数据也是企业进行营销的一个重要的生产要素。一直以来&#xff0c;营销的科学性正是因为运用了自然科学中一级互联网中的数据收集手段&#xff0c;严谨的记录、搜集和分析消费者的各项数据和日常生活…

Linux以系统服务的方式启动Kafka(其他服务同理)

最终效果&#xff1a; 先回顾命令行的启动方式&#xff1a; kafka的启动 进入kafka的安装目录 1、首先启动zookeeper服务&#xff1a; bin/zookeeper-server-start.sh config/zookeeper.properties2、再启动kafka bin/kafka-server-start.sh config/server.properties &…

vue3 DOM元素渲染完成之后执行

在Vue 3中&#xff0c;可以使用nextTick函数来在DOM元素渲染完成之后执行代码。nextTick函数会在下次DOM更新循环结束之后执行提供的回调函数。 例如&#xff0c;在Vue 3的组件中&#xff0c;可以这样使用nextTick函数&#xff1a; import { nextTick } from vue;export defa…

Vue实现Antv/X6中的示例,以及一些er图开发场景

通过Vue实现Antv X6中的示例&#xff0c;以及一些开发场景&#xff0c;代码已经丢到仓库里了。 lwstudy/antv-x6-vue-demo: Vue实现Antv X6中的示例&#xff0c;以及一些开发场景 (github.com)learn-antv-x6: antv/X6学习 (gitee.com) 介绍 使用脚手架&#xff08;自动生成接…

为了他的鸟,做件很叛逆很酷的事儿

有种鸟儿&#xff0c;叫隐鹮&#xff08;Geronticus eremita&#xff09;&#xff0c;大小如鹅&#xff0c;头部光秃&#xff0c;嘴巴巨大&#xff0c;一个字&#xff0c;丑。可是&#xff0c;它还有一个特点&#xff0c;面临濒危。 为了能在欧洲冬季存活&#xff0c;这种鸟儿需…

mfc140u.dll丢失如何修复?解析mfc140u.dll是什么文件跟修复方法分享

大家好&#xff01;今天&#xff0c;我将和大家分享一下关于计算机中mfc140u.dll丢失的6种解决方法。希望我的分享能对大家在计算机使用过程中遇到问题时提供一些帮助。 首先&#xff0c;我想请大家了解一下什么是mfc140u.dll文件。mfc140u.dll是一个动态链接库文件&#xff0…

java八股文面试[多线程]——进程与线程的区别

定义 1、进程&#xff1a;进程是一个具有独立功能的程序关于某个数据集合的以此运行活动。 是系统进行资源分配和调度的独立单位&#xff0c;也是基本的执行单元。是一个动态的概念&#xff0c;是一个活动的实体。它不只是程序的代码&#xff0c;还包括当前的活动。 进程结构…

W5100S-EVB-PICO主动PING主机IP检测连通性(十)

前言 上一章节我们用我们开发板在UDP组播模式下进行数据回环测试&#xff0c;本章我们用开发板去主动ping主机IP地址来检测与该主机之间网络的连通性。 什么是PING&#xff1f; PING是一种命令&#xff0c; 是用来探测主机到主机之间是否可通信&#xff0c;如果不能ping到某台…

【枚举区间】CF Edu10 C

Problem - C - Codeforces 题意&#xff1a; 思路&#xff1a; 应该反思一下这么典的思路为什么会想不到 枚举区间&#xff0c;一个很经典的套路是&#xff0c;枚举 l&#xff0c;对 r 计数 对于一个l&#xff0c;r取这么多限制中离 l 最近的那个 Code&#xff1a; #inclu…

一分钟科普:如何查看电脑型号?推荐五种常用方法,建议收藏

电脑型号是识别和区分不同电脑设备的关键。无论您是需要升级硬件、安装驱动程序&#xff0c;还是获取技术支持&#xff0c;了解电脑型号都能为您提供有用的信息。以下是几种查看电脑型号的方法&#xff1a; 方法一&#xff0c;物理标签查看法&#xff1a; 许多品牌的电脑在机身…

汽车服务门店小程序模板制作指南

在数字化时代&#xff0c;一个小程序的力量不可忽视。它不仅是展示品牌形象和提供用户服务的重要工具&#xff0c;更是扩大客户群体和提高营收的关键手段。对于汽车服务门店来说&#xff0c;拥有一个精美且功能齐全的小程序&#xff0c;更将成为你在竞争激烈的市场中的重要武器…

pdf文件打开后部分文字无法显示

场景&#xff1a;pdf文件在系统内预览正常&#xff0c;但是下载到本地电脑上&#xff0c;使用wps查看&#xff0c;部分标题会消失&#xff0c;只有标题里面的数字还能显示出来 经过一系列排查&#xff0c;发现查看的电脑上缺失了字体&#xff0c;使用wps查看时&#xff0c;缺失…

公交站牌部分代码

/*** 提交申请*/Log(title "维修业务", businessType BusinessType.UPDATE)PostMapping( "/submitApply/{id}")ResponseBodypublic AjaxResult submitApply(PathVariable Long id ,String variablesStr){try {System.out.println("variables: "…

多个Y轴的echarts图表组件

组件文件&#xff1a;<template><div class"wrap"><div ref"multipleLineChart" :style"{ height: height, width: width }" style"overflow:hidden"></div></div></template><script> exp…

【2D/3D RRT* 算法】使用快速探索随机树进行最佳路径规划(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

java八股文面试[多线程]——阻塞队列

阻塞队列大纲&#xff1a; 什么是阻塞队列 阻塞队列&#xff1a;从名字可以看出&#xff0c;他也是队列的一种&#xff0c;那么他肯定是一个先进先出&#xff08;FIFO&#xff09;的数据结构。与普通队列不同的是&#xff0c;他支持两个附加操作&#xff0c;即阻塞添加和阻塞删…

图像分类学习笔记(七)——MobileNet

一、MobileNetV1 传统的神经网络&#xff0c;内存需求大、运算量大&#xff0c;导致无法在移动设备以及嵌入式设备上运行。之前的VGG16模型权重大小大概有490M&#xff0c;ResNet模型权重大小大概有644M。MobileNet网络是由google团队在2017年提出的&#xff0c;专注于移动端或…

分析三维模型OBJ格式轻量化在网络传输中的重要性

分析三维模型OBJ格式轻量化在网络传输中的重要性 三维模型的OBJ格式轻量化在网络传输中扮演着重要的角色。随着互联网的快速发展和普及&#xff0c;越来越多的三维模型需要通过网络进行传输&#xff0c;涉及到下载、上传、共享等场景。而原始的三维模型文件往往较大&#xff0c…