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中的析构函数很可能或者必然将这个指针析构第二遍,导致错误发生,为了避免这个情况发生,需要定义一种行为,即当利用一个对象拷贝给另一个

对象的时候,需要对这种指针进行特殊处理,如图所示: 

iOS 深拷贝浅拷贝开发中的应用 深拷贝和浅拷贝代码_浅拷贝

 

 在深拷贝中(右图所示), 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,因此等号操作符重载就需要用深拷贝来实现