深拷貝和淺拷貝


深拷貝和淺拷貝可以簡單理解為:如果一個類擁有資源,當這個類的對象發生復制過程的時候,資源重新分配,這個過程就是深拷貝反之,沒有重新分配資源,就是淺拷貝。

===============================================

對於普通類型的對象來說,它們之間的復制是很簡單的,例如:
int a=88;
int b=a; 
而類對象與普通對象不同,類對象內部結構一般較為復雜,存在各種成員變量。下面看一個類對象拷貝的簡單例子。 

#include <iostream>
using namespace std;
class CExample {
private:
     int a;
public:
     CExample(int b)
     { a=b;}
     void Show ()
     {
        cout<<a<<endl;
    }
};
int main()
{
     CExample A(100);
     CExample B=A;
     B.Show ();
     return 0;
}

運行程序,屏幕輸出100。從以上代碼的運行結果可以看出,系統為對象B分配了內存並完成了與對象A的復制過程。就類對象而言,相同類型的類對象是通過拷貝構造函數來完成整個復制過程的。下面舉例說明拷貝構造函數的工作過程。

123456789101112131415161718192021222324252627 #include
<iostream>
using  namespace  std; class CExample {private:    int  a;public:  
 
CExample(int b)
    { a = b; }         CExample(const CExample& C)    {     a = C.a;    }    void Show ()    {    cout<<a<<endl;    }}; int main(){    CExample A(100);    CExample B=A;    B.Show ();    return 0;}

 

當用一個已初始化過了的自定義類類型對象去初始化另一個新構造的對象的時候,拷貝構造函數就會被自動調用。也就是說,當類的對象需要拷貝時,拷貝構造函數將會被調用以下情況都會調用拷貝構造函數:
(1)一個對象以值傳遞的方式傳入函數體 
(2)一個對象以值傳遞的方式從函數返回 
(3)一個對象需要通過另外一個對象進行初始化

如果在類中沒有顯式地聲明一個拷貝構造函數,那么,編譯器將會自動生成一個默認的拷貝構造函數,該構造函數完成對象之間的位拷貝。位拷貝又稱淺拷貝,后面將進行說明。

自定義拷貝構造函數是一種良好的編程風格,它可以阻止編譯器形成默認的拷貝構造函數,提高源碼效率。

淺拷貝和深拷貝

  在某些狀況下,類內成員變量需要動態開辟堆內存,如果實行位拷貝,也就是把對象里的值完全復制給另一個對象,如A=B。這時,如果B中有一個成員變量指針已經申請了內存,那A中的那個成員變量也指向同一塊內存。這就出現了問題:當B把內存釋放了(如:析構),這時A內的指針就是野指針了,出現運行錯誤。

 下面舉個深拷貝的例子。

1234567891011121314151617181920212223242526272829303132333435363738 #include
<iostream>
using namespace std;class CA{ public:  CA(int b,char* cstr)  {   a=b;   str=new char[b];   strcpy(str,cstr);  }  CA(const CA& C)  {   a=C.a;   str=new char[a];//深拷貝   if(str!=0)    strcpy(str,C.str);  }  void Show()  {   cout<<str<<endl;  }  ~CA()  {   delete str;  } private:  int a;  char *str;}; int main(){ CA
A(10,
"Hello!");
 CA
B=A;
 B.Show(); return 0;}

 

來總結一下關於 深拷貝與淺拷貝需要知道的基本概念和知識:

(1)什么時候用到拷貝函數?

  a.一個對象以值傳遞的方式傳入函數體; 
  b.一個對象以值傳遞的方式從函數返回;
  c.一個對象需要通過另外一個對象進行初始化。

如果在類中沒有顯式地聲明一個拷貝構造函數,那么,編譯器將會自動生成一個默認的拷貝構造函數,該構造函數完成對象之間的位拷貝。位拷貝又稱淺拷貝

(2)是否應該自定義拷貝函數?

(3)什么叫深拷貝?什么是淺拷貝?兩者異同?

自定義拷貝構造函數是一種良好的編程風格,它可以阻止編譯器形成默認的拷貝構造函數,提高源碼效率。 深如果一個類擁有資源,當這個類的對象發生復制過程的時候,資源重新分配,這個過程就是深拷貝,反之,沒有重新分配資源,就是淺拷貝。


(4)深貝好還是淺拷貝好?

如果實行位拷貝,也就是把對象里的值完全復制給另一個對象,如A=B。這時,如果B中有一個成員變量指針已經申請了內存,那A中的那個成員變量也指向同一塊內存。這就出現了問題:當B把內存釋放了(如:析構),這時A內的指針就是野指針了,出現運行錯誤。


==============           應用場景            ==========================

   淺 復 制:在復制操作時,對於被復制的對象的每一層復制都是指針復制。

   深 復 制:在復制操作時,對於被復制的對象至少有一層復制是對象復制。

   完全復制:在復制操作時,對於被復制的對象的每一層復制都是對象復制。

 

        注:1在復制操作時,對於對象有n層是對象復制,我們可稱作n級深復制,此處n應大於等於1。

              2對於完全復制如何實現(目前通用的辦法是:迭代法和歸檔),這里后續是否添加視情況而定,

              暫時不做講解。

          3、指針復制俗稱指針拷貝,對象復制也俗稱內容拷貝。

          4、一般來講,

                 淺層復制:復制引用對象的指針。 

                 深層復制:復制引用對象內容。            這種定義在多層復制的時候,就顯得模糊。所以本文定義與它並不矛盾。            反而是對它的進一步理解和說明。           

 

retain:始終是淺復制。引用計數每次加一。返回對象是否可變與被復制的對象保持一致。 

copy:對於可變對象為深復制,引用計數不改變;對於不可變對象是淺復制,  引用計數每次加一。始終返回一個不可變對象。 

mutableCopy:始終是深復制,引用計數不改變。始終返回一個可變對象。

 

   可變對象:值發生改變,其內存首地址隨之改變。

   不可變對象:無論值是否改變,其內存首地址都不隨之改變。

   引用計數:為了讓使用者清楚的知道,該對象有多少個擁有者(即有多少個指針指向同一內存地址)。

 

 最近有一個好朋友問我,什么時候用到深淺復制呢?那么我就把我所總結的一些分享給大家,希望能幫助你們更好的理解深淺復制!

 

那么先讓我們來看一看下邊數組類型的轉換

1、不可變對象→可變對象的轉換:

       NSArray *array1= [NSArray arrayWithObjects:@"a",@"b",@"c",@"d",nil];

       NSMutableArray  *str2=[array1 mutableCopy];

2、可變對象→不可變對象的轉換:

    NSMutableArray *array2   = [NSMutableArray arrayWithObjects:@"aa",@"bb",@"cc",@"dd",nil];

       NSArray *array1=[  array2    Copy];

3、可變對象→可變對象的轉換(不同指針變量指向不同的內存地址):

       NSMutableArray *array1= [NSMutableArray arrayWithObjects:@"a",@"b",@"c",@"d",nil];

       NSMutableArray  *str2=[array1 mutableCopy];

通過上邊的兩個例子,我們可輕松的將一個對象在可變和不可變之間轉換,並且這里不用考慮內存使用原則(即引用計數的問題)。沒錯,這就是深拷貝的魅力了。

4、同類型對象之間的指針復制(不同指針變量指向同一塊內存地址):

  a、

   NSMutableString *str1=[NSMutableString stringWithString:@"two day"];

   NSMutableString *str2=[str1   retain];

   [str1  release];

  b、

   NSArray *array1= [NSArray arrayWithObjects:@"a",@"b",@"c",@"d",nil];

   NSArray  *str2=[array1 Copy];

   [array1 release];

 

   通俗的講,多個指針同時指向同一塊內存區域,那么這些個指針同時擁有對該內存區的所有權。所有權的瓜分過程,這時候就要用到淺拷貝了。

則簡化為:

問:什么時候用到深淺拷貝?

答:深拷貝是在要將一個對象從可變(不可變)轉為不可變(可變)或者將一個對象內容克隆一份時用到;

      淺拷貝是在要復制一個對象的指針時用到。

 

 

 

 

 



注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



深拷貝與淺拷貝 深拷貝-淺拷貝 淺拷貝與深拷貝 深拷貝和淺拷貝 關於深拷貝淺拷貝 淺拷貝和深拷貝 淺拷貝和深拷貝 淺拷貝與深拷貝 淺拷貝和深拷貝 淺拷貝和深拷貝
 
粤ICP备14056181号  © 2014-2021 ITdaan.com