C++(day 8)一张图教你看懂浅拷贝和深拷贝

回顾默认拷贝构造函数

默认拷贝构造函数的策略就是逐个逐个成员依次拷贝。
示例代码:

#include<iostream>
using namespace std;
class Person
{
public:
	Person(int id)
	{
		_id = id;
	}
	void display()
	{
		cout << _id << endl;
	}
private:
	int _id;
};

int main()
{
	Person person1(20200501);
	person1.display();
	Person person2 = person1;
	person2.display();
}

运行结果:
运行结果
在Person person2 = person1时进行了依次拷贝。

一张图看懂浅拷贝和深拷贝

浅拷贝和深拷贝的区别就是拷贝的深度
浅拷贝
这就是浅拷贝,只拷贝了成员数据的二进制数值。如上图中pName指针中存放的是指向某个堆空间的地址,拷贝后对象2的pName指针的值是相同的,也就是指向了同一个堆空间的地址。下面我们来看一下深拷贝的情况:
在这里插入图片描述

相比浅拷贝,深拷贝不是拷贝表面上pName的值,而是深入pName指向的堆区域把该堆区域的资源拷贝了一份。深拷贝是需要我们自己写拷贝构造函数的。

实例

浅拷贝和深拷贝的区别我们已经知道了,那么我们看看实际的代码。

浅拷贝

#include<iostream>
using namespace std;
class Person
{
public:
	Person(const char * pN)
	{
		cout << "Constructing " << pN << endl;
		pName = new char[strlen(pN) + 1];
		if (pName != 0)
		{
			strcpy(pName, pN);
		}
	}
	~Person()
	{
		cout << "Destructing " << pName << endl;
		pName[0] = '\0';
		delete pName;
	}
protected:
	char* pName;
};

int main()
{
	Person p1("Randy");
	Person p2 = p1;
}

程序刚开始运行时,创建p1对象,p1对象的构造函数从堆中分配空间并赋给数据成员pName,接着输出第一条语句。执行Person p2 = p1时,由于没有定义拷贝构造函数,于是就调用默认拷贝构造函数,将p1的值复制给p2,它们的成员pName指向同一个地址,并没有新分配堆空间给p2。这样就造成了资源将经历两次资源返还:当主函数结束时,对象逐个析构,析构p2时,输出第二条语句,将堆中字符串清成空串,然后将堆空间返还给系统。当析构p1时,因为这是pName指向的是空串,所以输出的第三条语句是"Destructing ";当执行"delete pName"时,系统就报错了,原因是分配的指针不存在了。

深拷贝

为了解决上述问题,必须要使用深拷贝。

#include<iostream>
#include<string.h>
using namespace std;
class Person
{
public:
	Person(const char * pN)
	{
		cout << "Constructing " << pN << endl;
		pName = new char[strlen(pN) + 1];
		if (pName != 0)
		{
			strcpy(pName, pN);
		}
	}
	Person(Person& p)
	{
		cout << "Copying " << p.pName << " into its own block\n";
		pName = new char[strlen(p.pName)+1];
		if (pName != 0)
			strcpy(pName, p.pName);
	}
	~Person()
	{
		cout << "Destructing " << pName << endl;
		pName[0] = '\0';
		delete pName;
	}
protected:
	char* pName;
};

int main()
{
	Person p1("Randy");
	Person p2 = p1;
}

在代码中自行写了一个拷贝构造函数,在拷贝过程中用new语句分配了新的堆空间给新对象使用,因此解决了资源经历两次资源返还的问题。
总结,浅拷贝与深拷贝的不同是:前者只拷贝了成员的数值,而后者把使用的资源也拷贝了。
如果你的类需要析构函数来析构资源,则它也需要一个拷贝构造函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值