深拷贝与浅拷贝

一   深浅拷贝概念

首先明白深浅拷贝是针对拷贝构造函数和赋值运算符重载而言的

所谓浅拷贝,就是由默认的拷贝构造函数所实现的对数据成员依次赋值,若类中含有指针类型的  数据,这种方式只是简单的把指针的指向赋值给新成员,但并没有给新成员分配内存导致两个成员指针指向同一块内存,要是再分别delete释放时就会出现问题,因此这种方式必然会导致错误,为了解决浅拷贝出现的错误,必须显示定义一个拷贝构造函数。使之不但复制数据成员,而且为对象分配各自的内存 空间,这就是所谓的深拷贝

二  浅拷贝

浅拷贝就是由默认的拷贝构造函数所实现的数据成员逐一赋值。通常默认的拷贝构造函数能够胜任这个工作,但若是类中含有指针类型的数据,这种数据成员逐一赋值的方式将产生错误。

以string为例讲解:我们先来看一下构造函数

           


上面这张图,我没有自己编写拷贝构造,因此用的是系统自动合成的,也就是说s2,s3指向同一块空间,调用两次析构函数,把堆上分配的空间释放了两次,因此出错



上面这张赋值运算符重载有两个错误:1.s1原来指向空间内存泄露   2.同一块空间被析构了两次

三  深拷贝


为了解决浅拷贝出现的错误,必须显示定义一个拷贝构造函数,使之不但能复制数据成员,而且为指针分配各自的动态内存

传统写法:老老实实开辟空间

具体实现代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class String
{
public:
	/*String(char*str="")
	:_str(new char[strlen(str)+1])
	{
	strcpy(_str, str);
	}*/
	String(char*str)
		:_str(new char[strlen(str) + 1])
	{
		strcpy(_str, str);
	}
	String()
		:_str(new char[1])//原因:1.这块必须分配一个空间,不然底下赋值运算符重载,释放_str之前就要判断是否为空   //2.因为析构用的是delete[],因此必须new[]
	{
		*_str = '\0';
	}

	char* Getstr()
	{
		return _str;
	}
	~String()
	{
		if (_str)
			delete[]_str;
		_str = NULL;
	}

String ( const String& s)
{
    _str = new char[strlen(s._str) + 1];          //1.分配空间拷贝
    strcpy(_str, s._str);                         //2.拷贝

}
String& operator =(const String&s)
{
	if (this != &s)
	{
		delete[]_str;                         // 1.释放s1原来指向的空间
		_str = new char[strlen(s._str) + 1]; //2.分配一块与s2大小相同的空间
		strcpy(_str, s._str);               //3.拷贝
	}
	return *this;
}

private:
	char* _str;
};
int main()
{
	String s1("change world");
	String s2("hello world");
	String s3(s2);
	s1 = s2;
	cout << s2.Getstr() << endl;
	cout << s3.Getstr() << endl;
	cout << s1.Getstr() << endl;
	system("pause");
	return 0;
}

现代写法:让别人做,让构造函数做

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<math.h>
using namespace std;
class String
{
public:
	/*String(char*str="")
	:_str(new char[strlen(str)+1])
	{
	strcpy(_str, str);
	}*/
	String(char*str)
		:_str(new char[strlen(str) + 1])
	{
		strcpy(_str, str);
	}
	String()
		:_str(new char[1])//原因:1.这块必须分配一个空间,不然底下赋值运算符重载,释放_str之前就要判断是否为空   //2.因为析构用的是delete[],因此必须new[]
	{
		*_str = '\0';
	}

	char* Getstr()
	{
		return _str;
	}
	~String()
	{
		if (_str)
			delete[]_str;
		_str = NULL;
	}

String ( const String& s)
     :_str(NULL)
{
	String tmp(s._str);
	swap(_str, tmp._str);

}

String& operator =(const String&s)//赋值运算符重载2
{
	if (this != &s)
	{
		String tmp(s);//调拷贝构造  或者调构造函数 String tmp(s._str)
		swap(_str, tmp._str);
	}
	return *this;
	
}
String& operator=( String s)//赋值运算符重载3       参数不是引用,因此会创建一个形参,调拷贝构造
{
	swap(_str, s._str);
	return *this;
}
private:
	char* _str;
};
int main()
{
	String s1("change world");
	String s2("hello world");
	String s3(s2);
	s1 = s2;
	cout << s2.Getstr() << endl;
	cout << s3.Getstr() << endl;
	cout << s1.Getstr() << endl;
	system("pause");
	return 0;
}
深浅拷贝就讲到这儿。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值