浅谈深拷贝与浅拷贝

浅拷贝:利用类提供的默认拷贝构造函数,将一个对象的成员所在内存的数据复制给另一个对象的成员。

对于简单的类来说,使用浅拷贝就可以满足正常需求了,但是当类中有指向动态内存的指针时,浅拷贝的使用很容易造成内存错误,就需要显式定义拷贝构造函数。

浅拷贝错误案例

一起看一个浅拷贝的案例:

#include<iostream>
using namespace std;
#include<memory>

class Base
{
public:
	Base(int A, int B)
	{
		m_A = A;
		m_B = new int(B);
	}

	~Base()
	{
		delete m_B;
		m_B = NULL;
	}
	
public:
	int m_A;
	int* m_B;
};


int main()
{
	Base b(10, 20);
	cout << "m_B的值为:" << b.m_B << "  m_B所指向的值为:" << *(b.m_B) << endl;
	Base c(b);  //默认拷贝构造函数
	cout << "m_B的值为:" << c.m_B << "  m_B所指向的值为:" << *(c.m_B) << endl;

	system("pause");
	return 0;
}

运行结果如下:
在这里插入图片描述
结果看起来好像没啥问题,但是当我按任意键结束主程序时,发现程序崩了,如下:
在这里插入图片描述
那么这是什么原因呢?我们先看一下,对象b和c的内存关系如下:
在这里插入图片描述
可以看到,对象b和c中的m_B储存的都是形参B的地址,而B的值为20。也就是说对象c拷贝对象b的时候,c.m_B只是拷贝了b.m_B的值,即B的地址,所以c.m_B和b.m_B都是指向变量B的指针。

默认的拷贝构造函数可写为:

	//浅拷贝
	Base(const Base& _Base)
	{
		this->m_A = _Base.m_A;  
		this->m_B = _Base.m_B;; 
	}

在主程序结束的时候,会先销毁对象b,此时b.m_B指向的B的内存资源也会被释放,那么,程序继续销毁对象c时,指针c.m_B也要释放B的内存资源,就会造成重复释放内存,从而出现错误。

深拷贝

针对浅拷贝的问题,就需要通过深拷贝来解决。所谓深拷贝,就是显式定义类的拷贝构造函数,不仅会将原对象的成员变量复制给新对象,还会在堆中为新对象分配一块新的内存,并将原对象持有的动态内存资源也拷贝过来。

那么,看一下用深拷贝重新实现上面的代码:

#include<iostream>
using namespace std;
#include<memory>

class Base
{
public:
	Base(int A, int B)
	{
		m_A = A;
		m_B = new int(B);
	}
	
	//深拷贝
	Base(const Base& _Base)
	{
		this->m_A = _Base.m_A;
		int temp = *(_Base.m_B);   
		this->m_B = new int(temp);  //在堆中开辟新内存存储变量temp
	}

	~Base()
	{
		delete m_B;
		m_B = NULL;
	}
	
public:
	int m_A;
	int* m_B;
};


int main()
{
	Base b(10, 20);
	cout << "m_B的值为:" << b.m_B << "  m_B所指向的值为:" << *(b.m_B) << endl;
	Base c(b);  //默认拷贝构造函数
	cout << "m_B的值为:" << c.m_B << "  m_B所指向的值为:" << *(c.m_B) << endl;

	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述
可以看到,运行结果与浅拷贝的结果一样,但是在主程序结束时并不会出现内存错误。可以看一下深拷贝的内存关系,如下图:
在这里插入图片描述
可以看到,b.m_B和c.m_B的值是不一样的,即存储的地址不一样。也就是说,在深拷贝的过程中,对象c在堆区中重新开辟了一块内存空间,存储着与b中动态内存相同的资源,且指针c.m_B指向这块新的资源。因此,在主程序结束的时候,销毁对象b时就释放其对应的内存资源,销毁对象c时就释放其对应的内存资源,不会发生内存错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值