1. 介绍
深拷贝与浅拷贝并非c++的特性,而是在编程语言中普遍存在的,在实际应用中初学者也并不要望而却步,其实没什么难的,相信看过我的文章之后大家都能很熟练的掌握它,书写自己的拷贝函数。
为了能够更直观的介绍深拷贝与浅拷贝, 首先我们先抛开c++不谈,给出一个python的表达式,从这个表达式入手,我们来分析它背后到底发生了什么
在python中,如果存在a=b, 我们象征性的会认为,b值赋给a值,这是没错的,但是如果就此止步那么就没有我们下面讨论的问题了,先看个小程序:
a=5
b=6
a=b
b=7
print a
结果不能想当然,运行结果为6, 再看:
a=[1,2,3]
b=[4,5,6]
a=b
b=[7,8,9]
print a
结果为[7,8,9]
结论: 根据数据类型不同,赋值操作背后的含义也是不同的,从类的角度来讲,其实就是=操作符重载的实现不同罢了
2. 概念
浅拷贝: 拷贝对象时,将对象中的数据(指针,引用,普通数据)进行简单的值拷贝
深拷贝: 拷贝对象时,当对象中存在指针,引用时,为了防止多个指针指向同一个内存空间,在拷贝时另外开辟一份空间,防止析构发生混乱
由于数据结构有时会复杂,包含堆指针,在完成算法后,这些指针需要在析构函数或者特定的函数中被释放,试想,如果一个包含这种指针的对象A简单的将对象数据包括指针赋值给B,那么B是无法得知A什么时候析构的,
在大型程序中B由于无法得知或者很难得知A的析构情况,B中的析构函数很可能或者必然将这个指针析构第二遍,导致错误发生,为了避免这个情况发生,需要定义一种行为,即当利用一个对象拷贝给另一个
对象的时候,需要对这种指针进行特殊处理,如图所示:
在深拷贝中(右图所示), B对象将会重新new一份空间出来,而真正拷贝到B中的是A中的指针所指向空间的内容,这样一来,B就不会再关心A什么时候析构了,因为两块堆内存都有自己的指针,相互不依赖
3. 实现
有时我们需要用一个已经存在的对象去初始化一个新的对象,此时就根据需要使用深拷贝,因为涉及到初始化,就需要使用拷贝构造函数了
下面给出一个示例代码供参考:
class Deep_Copy
{
public:
Deep_Copy() //默认构造函数,初始化
{
this->deep_copy_len = 0;
this->deep_data = 0;
this->deep_copy_p = nullptr;
}
Deep_Copy(Deep_Copy &obj)
{
this->deep_copy_len = obj.deep_copy_len;
this->deep_data = obj.deep_data;
this->deep_copy_p = new char(this->deep_copy_len);
//当然,这里也可以用标准库函数直接进行拷贝的操作
for(int i=0; i<this->deep_copy_len; i++)
{
*(this->deep_copy_p+i) = *(obj.eep_copy_p+i)
}
}
Deep_Copy& operator=(Deep_Copy &obj)
{
this->deep_copy_len = obj.deep_copy_len;
this->deep_data = obj.deep_data;
this->deep_copy_p = new char(this->deep_copy_len);
for(int i=0; i<this->deep_copy_len; i++)
{
*(this->deep_copy_p+i) = *(obj.eep_copy_p+i)
}
return (*this);
}
~Deep_Copy()
{
if(this->deep_copy_p != nullptr)
{
delete [] this->deep_copy_p;
this->deep_copy_p = nullptr;
}
}
char *deep_copy_p;
int deep_copy_len;
char deep_data;
};
值得注意的是,析构函数由于并不知道对象是由拷贝构造函数得来的,还是由默认构造函数得来的,需要判断指针是否为空,再进行析构
程序中也提供了等号操作符重载的实现,在进行A=B的操作时,默认会将B进行浅拷贝到A,因此等号操作符重载就需要用深拷贝来实现
原文:https://www.cnblogs.com/shaguargeffon/p/14966966.html