深拷貝與淺拷貝到底是什麼

複製構造函數也叫拷貝構造函數;
淺複製也叫淺拷貝或位拷貝;
深複製也叫深拷貝;
淺拷貝和深拷貝
拷貝就是複製,創建副本。假設有對象A,A有屬性t1,t2。那麼,我通過拷貝A,得到B,B應該也有屬性t1,t2,且A、B兩個對象的每個屬性,都應該是相同的。
對於基本類型的屬性t1,拷貝是沒有疑義的。簡單將值複製一份,就達到了拷貝的效果。而對於引用類型的屬性t2來說,拷貝就有了兩層含義。
第一層是,我只是將t2引用的地址複製一份給B的t2,確實達到了屬性相同的效果,可以理解爲實現了拷貝,但是事實上,兩個對象中的屬性t2對應的是同一個對象。在B對象上對t2所指向的對象進行操作,就會影響到A對象中的t2的值。
第二層是,我將A的t2所指向的對象,假設爲o1,完整複製一份,假設爲o2,將新的o2的地址給B的t2。也達到了複製的效果,且對B的t2所指向的o2進行操作,不會影響到A的t2所指向的o1。
拷貝的兩層含義,對應了淺拷貝和深拷貝的概念,做了第一層,就是淺拷貝,做到第二層,就是深拷貝。
在這裏插入圖片描述
基於以上內容,很容易可以想到,淺拷貝比深拷貝要更快,但是,從拷貝的意義上來看,淺拷貝相較於深拷貝,要欠缺一點。

實例如下:


#include <iostream>
using namespace std;
//20200430 歡迎關注公衆號:C語言與CPP編程

class CopyDemo
{
public:
  CopyDemo(int pa,char *cstr)  //構造函數,兩個參數
  {
     this->a = pa;
     this->str = new char[1024]; //指針數組,動態的用new在堆上分配存儲空間
     strcpy(this->str,cstr);    //拷貝過來
  }

//沒寫,C++會自動幫忙寫一個複製構造函數,淺拷貝只複製指針,如下注釋部分
  //CopyDemo(CopyDemo& obj)  
  //{
  //   this->a = obj.a;
  //  this->str = obj.str; //這裏是淺複製會出問題,要深複製
  //}

  CopyDemo(CopyDemo& obj)  //一般數據成員有指針要自己寫複製構造函數,如下
  {
     this->a = obj.a;
    // this->str = obj.str; //這裏是淺複製會出問題,要深複製
     this->str = new char[1024];//應該這樣寫
     if(str != 0)
        strcpy(this->str,obj.str); //如果成功,把內容複製過來
  }

  ~CopyDemo()  //析構函數
  {
     delete str;
  }

public:
     int a;  //定義一個整型的數據成員
     char *str; //字符串指針
};

int main()
{
  CopyDemo A(100,"hello!!!");

  CopyDemo B = A;  //複製構造函數,把A的10和hello!!!複製給B
  cout <<"A:"<< A.a << "," <<A.str << endl;
  //輸出A:100,hello!!!
  cout <<"B:"<< B.a << "," <<B.str << endl;
  //輸出B:100,hello!!!

  //修改後,發現A,B都被改變,原因就是淺複製,A,B指針指向同一地方,修改後都改變
  B.a = 80;
  B.str[0] = 'k';

  cout <<"A:"<< A.a << "," <<A.str << endl;
  //輸出A:100,kello!!!
  cout <<"B:"<< B.a << "," <<B.str << endl;
  //輸出B:80,kello!!!

  return 0;
}

根據上面實例可以看到,淺複製僅複製對象本身(其中包括是指針的成員),這樣不同被複制對象的成員中的對應非空指針會指向同一對象,被成員指針引用的對象成爲共享的,無法直接通過指針成員安全地刪除(因爲若直接刪除,另外對象中的指針就會無效,形成所謂的野指針,而訪問無效指針是危險的;除非這些指針有引用計數或者其它手段確保被指對象的所有權);而深複製在淺複製的基礎上,連同指針指向的對象也一起復制,代價比較高,但是相對容易管理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章