浅拷贝和深拷贝

一、什么是深拷贝和浅拷贝

    简单的来说,【浅拷贝】是增加了一个指针,指向原来已经存在的内存。而【深拷贝】是增加了一个指针,并新开辟了一块空间让指针指向这块新开辟的空间。浅拷贝只是增加了指向同一个空间的对象。而深拷贝则是新建了全新的对象,它具有自己的空间。对于一个空类,编译器默认生成四个成员函数:默认构造函数、析构函数、拷贝构造函数、赋值函数。而直立棉的拷贝构造函数是浅拷贝。所以这时候如果类中含有指针变量,默认的拷贝构造函数必定出错。

二、浅拷贝

    这里给出一个浅拷贝的例子。

#include <iostream>
#include <string>

using namespace std;

class String
{
public:
	// 构造函数
	String(const char* pStr = "")
	{
		if (NULL == pStr)
		{
			pstr = new char[1];
			*pstr = '\0';
		}
		else
		{
			pstr = new char[strlen(pStr) + 1]; // 加1, 某位是'\0',结束符
			strcpy(pstr, pStr);
		}
	}

	// 拷贝构造函数
	String(const String& s)
	{
		pstr = s.pstr; // 浅拷贝的问题,指向同一块空间,可能造成释放的错误 ,这是浅拷贝的缺点
	}

	// 赋值运算符重载
	String& operator = (const String& s)
	{
		if (this != &s)
		{
			delete[] pstr; // 将原来所指向的空间释放
			pstr = s.pstr; // 让pstr重新指向s的pstr所指向的空间(也会导致错误)   
		}

		return *this;
	}

	~String()
	{
		// 2. 插入断点
		if (NULL != pstr)
		{
			delete[] pstr;//释放指针所指向的内容   
			pstr = NULL;//将指针置为空      
		}
	}
	friend ostream& operator<<(ostream& _cout, const String& s)
	{
		_cout << s.pstr;
		return _cout;
	}

private:
	char* pstr;
};

int main()
{
	// 1. 插入断点
	String s1("sss");
	String s2(s1);
	String s3(NULL);
	s3 = s1;
	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	return 0;
}

    这里我们将三个对象添加到监视里,发现他们的地址都是一样。
在这里插入图片描述
    在析构函数处插入断点,析构s3时,将空间释放掉了,可以析构s2的时候报错了。因为它地址所处的空间就是s3的空间,以及被释放掉了,所以报错了。
在这里插入图片描述

三、深拷贝

    深拷贝和浅拷贝的不同之处,仅仅在于修改了下【拷贝构造函数】,以及【赋值运算符的重载】。其实是给每个新建的对象分配了空间。

	// 拷贝构造函数
	String(const String& s)
	{
		pstr = new char[strlen(s.pstr) + 1];
		strcpy(pstr, s.pstr);
	}

	// 赋值运算符重载
	String& operator = (const String& s)
	{
		if (this != &s)
		{
			char* tmp = new char[strlen(s.pstr) + 1];//动态开辟一个临时变量,然后将pstr指向这一个新的临时变量里  
			delete[] pstr;//将原来的空间进行释放  
			strcpy(tmp, s.pstr);//将s.pstr里的内容复制到临时变量中  
			pstr = tmp;//pstr指向临时变量的这段空间  
		}

		return *this;
	}

    现在可以看出三个对象的地址都不一样了,程序运行没有问题了。
在这里插入图片描述
    这边可以简化一下深拷贝的【拷贝构造函数】,【赋值运算符重载】

	// 拷贝构造函数
	String(const String& s)
	{
		// 调用构造函数
		String temp(s.pstr);
		swap(pstr, temp.pstr);
	}

	// 赋值运算符重载
	String& operator = (const String& s)
	{
		if (this != &s)
		{
			// 调用构造函数
			String temp(s.pstr);
			swap(pstr, temp.pstr);
		}

		return *this;
	}

四、总结

  • 浅拷贝只是增加了一个指针,指向已存在对象的内存。
  • 浅拷贝在多个对象指向一块空间的时候,释放一个空间会导致其他对象所使用的空间也被释放了,再次释放便会出现错误
  • 深拷贝是增加了一个指针,并新开辟了一块空间,让指针指向这块新开辟的空间。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值