C++57个入门知识点_24_ 浅拷贝与深拷贝(浅拷贝:对象1、2均指向一块内存; 深拷贝:重新分配内存,将对象1内容复制给对象2;何时重写拷贝构造函数:对象成员非基本数据类型,为资源时需重写或禁用)

上篇C++57个入门知识点_23_ 拷贝构造函数(利用一个对象创建另一个对象,调用的构造函数即拷贝构造函数;缺省下为完全拷贝;手写即CStudent(CStudent& obj) {…}-对象做参数)介绍了拷贝构造函数的使用,本篇将会介绍拷贝构造函数有哪些需要注意的事项。

总结:

1. 浅拷贝: 是将对象1拷贝给对象2,对象1、2均指向一块内存,会存在重复释放导致程序崩溃的问题
2. 深拷贝: 自己写拷贝构造函数重新分配内存,将对象1的内容复制给对象2,避免重复释放问题
3. 何时重写拷贝构造函数: 当类对象中的成员不是基本数据类型,存在一种需要分配的资源时(堆空间,例如使用:m_szName = (char*)malloc(255)创建的动态内存、或者可能是文件的句柄、或者其他分配的资源),为了避免在析构时重复释放,需要重写拷贝构造函数或禁用
4. 基本数据类型不存数据释放的问题,只有资源才会涉及内存申请和释放

上篇我们使用默认的构造函数,利用一个对象创建另一个对象时,运行过程中由于原对象和创建的对象指向的内容完全一致,在析构时由于要析构两次,第二次析构时由于第一次析构已经将内存释放,再去析构就出现了程序崩溃的问题。

1. 浅拷贝

缺省的拷贝构造函数即为浅拷贝,其作用为:

  • 完全把对象1拷贝给对象2;
  • 内存的拷贝(浅拷贝,对象1、2均指向一块内存)

浅拷贝在释放时会两次释放同一块内存,因此在第二次释放时由于内存已经释放过一次,因此会造成崩溃

浅拷贝的拷贝构造函数写法:


	CStudent(CStudent& obj) {

		printf("CStudent(CStudent& obj) \r\n");

		//浅拷贝:将对象1的值赋值给对象2
		//如果只是基本数据类型就不存数据释放的问题,而此处是一个资源,涉及内存的申请和释放,下句的含义是对象1和2都指向同一个内存块
		this->m_szName = obj.m_szName;
	}

2. 深拷贝

深拷贝就可以解决上面浅拷贝析构两次导致程序崩溃的问题,自己写拷贝构造函数重新分配内存,将对象1的内容复制给对象2

一张图看懂:
在这里插入图片描述
深拷贝的拷贝构造函数的写法:

//通过引用的方式,将一个对象拷贝给另一个对象
	CStudent(CStudent& obj) {
	
		printf("CStudent(CStudent& obj) \r\n");

		//重新分配空间
		m_szName = (char*)malloc(255);//c语言中在堆上创建动态内存
		if (m_szName == nullptr) {
			return;
		}
		//深拷贝,把对象1的内容复制给对象2
		memcpy(this->m_szName,obj.m_szName,255);

	}

运行结果:对象1和2内容一样,但是指向了不同的堆空间地址,在进行析构的时候就会分别进行析构,从而避免浅拷贝出现的问题
在这里插入图片描述

3. 何时需要重写拷贝构造函数


当类对象中的成员函数存在一种需要分配的资源时(堆空间,例如使用:m_szName = (char*)malloc(255)创建的动态内存、或者可能是文件的句柄、或者其他分配的资源),为了避免在析构时重复释放,需要重写拷贝构造函数或禁用。

4.学习视频地址:C++57个入门知识点_24_ 浅拷贝与深拷贝

5.程序代码

#include <iostream>

class CStudent {

public:
	CStudent() {
		printf("CStudent()\r\n");
		//为了m_szNam创建一个堆空间(分配动态内存)
		m_szName = (char*)malloc(255);
     }

	//为了初始化方便,使用带有参数的构造
	CStudent(const char* pName, int nlength) {

		printf("CStudent(char* pName, int nlength)\r\n");

		//判断缓存要求是否大于255,大于255就返回
		if (nlength > 255) {
			return;
		}

		//为m_szNam创建一个堆空间(分配动态内存)
		m_szName = (char*)malloc(255);//c语言中在堆上创建动态内存
		//判断堆上创建的内存是否为空,空则返回
		if (m_szName == nullptr) {
			return;
		}
		memcpy(m_szName, pName, nlength);

	}

	//通过引用的方式,将一个对象拷贝给另一个对象
	CStudent(CStudent& obj) {

		printf("CStudent(CStudent& obj) \r\n");

		//浅拷贝
		//如果为普通数据类型这种是没有问题,但是此处是资源,涉及内存的申请和释放,下句的含义是指向同一个内存块
		//this->m_szName = obj.m_szName;

		//重新分配空间
		m_szName = (char*)malloc(255);//c语言中在堆上创建动态内存
		if (m_szName == nullptr) {
			return;
		}
		//深拷贝,把对象1的内容复制给对象2
		memcpy(this->m_szName, obj.m_szName, 255);

	}

	~CStudent() {
		free(m_szName);
		printf("~CStudent()\r\n");
	}

	void SetName(const char* pszName){}

private:
	int m_nStudID;//学号
	char* m_szName;
};

int main(int argc, char* argv[])
{
	//创建对象进行构造,strlen("张三")+1是为了包含结尾
	CStudent stu("张三", strlen("张三") + 1);

	//利用已经定义的对象定义另一个对象
	CStudent stu2 = stu; //将stu对象赋值给stu2 类似于int n=1;int k=n;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十月旧城

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值