欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

深拷贝与浅拷贝

程序员文章站 2022-05-28 14:29:58
...

一   深浅拷贝概念

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

所谓浅拷贝,就是由默认的拷贝构造函数所实现的对数据成员依次赋值,若类中含有指针类型的  数据,这种方式只是简单的把指针的指向赋值给新成员,但并没有给新成员分配内存导致两个成员指针指向同一块内存,要是再分别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;
}
深浅拷贝就讲到这儿。



相关标签: 深拷贝 浅拷贝