C 深拷貝與淺拷貝

2021-08-15 10:18:32 字數 2495 閱讀 8173

對於普通型別的物件來說,它們之間的複製是很簡單的,例如:

int a=88;

int b=a;

而類物件與普通物件不同,類物件內部結構一般較為複雜,存在各種成員變數。下面看乙個類物件拷貝的簡單例子。

#include 

using

namespace

std;

class cexample

void show ()

執行程式,螢幕輸出100。從以上**的執行結果可以看出,系統為物件b分配了記憶體並完成了與物件a的複製過程。就類物件而言,相同型別的類物件是通過拷貝建構函式來完成整個複製過程的。下面舉例說明拷貝建構函式的工作過程。

#include 

using

namespace

std;

class cexample

cexample(const cexample& c)

void show ()

cexample(const cexample& c)就是我們自定義的拷貝建構函式。可見,拷貝建構函式是一種特殊的建構函式,函式的名稱必須和類名稱一致,它的唯一的乙個引數是本型別的乙個引用變數,該引數是const型別,不可變的。例如:類x的拷貝建構函式的形式為x(x& x)。

為什麼拷貝建構函式的引數一定要是引用呢?

如果不用引用,為了呼叫拷貝建構函式我們必須拷貝它的實參,但為了拷貝實參我們有需要呼叫拷貝建構函式,如此形成了死迴圈。

當用乙個已初始化過了的自定義類型別物件去初始化另乙個新構造的物件的時候,拷貝建構函式就會被自動呼叫。也就是說,當類的物件需要拷貝時,拷貝建構函式將會被呼叫。以下情況都會呼叫拷貝建構函式:

乙個物件以值傳遞的方式傳入函式體。

乙個物件以值傳遞的方式從函式返回。

乙個物件需要通過另外乙個物件進行初始化。

如果在類中沒有顯式地宣告乙個拷貝建構函式,那麼,編譯器將會自動生成乙個預設的拷貝建構函式,該建構函式完成物件之間的位拷貝。位拷貝又稱淺拷貝,後面將進行說明。

自定義拷貝建構函式是一種良好的程式設計風格,它可以阻止編譯器形成預設的拷貝建構函式,提高原始碼效率。

在某些狀況下,類內成員變數需要動態開闢堆記憶體,如果實行位拷貝,也就是把物件裡的值完全複製給另乙個物件,如a=b。這時,如果b中有乙個成員變數指標已經申請了記憶體,那a中的那個成員變數也指向同一塊記憶體。這就出現了問題:當b把記憶體釋放了(如:析構),這時a內的指標就是野指標了,出現執行錯誤。

深拷貝和淺拷貝可以簡單理解為:如果乙個類擁有資源,當這個類的物件發生複製過程的時候,資源重新分配,這個過程就是深拷貝,反之,沒有重新分配資源,就是淺拷貝。下面舉個深拷貝的例子。

#include 

using namespace std;

class

ca  ca(const ca& c)

void show()

private:

int a;

char *str;

};int main()

以上內容主要**:

下面的是**知乎上藍色大神的回答,加深理解:

我認為淺拷貝是乙個不喜歡思考的懶漢,而深拷貝則是乙個思維嚴謹,喜歡思考的人。對於懶漢來說,雖然給了他任務,但是他總是想盡量的少做一些事情,所以很多時候做出來的東西就是只看到了表面,不會去思考對不對。

struct x

;

對於懶漢來說,他很直白的看到了x,看到了y,然後就拷貝x和y,然後就不管了,反正我完成我的拷貝了,至於對不對,我不管。

而一旦有了引用或者指標,事情就不一樣了。

struct x

;

懶漢依然只是直接表面級別的拷貝,於是拷貝x, y , p,但是他沒有思考接下來的事情對不對。對於指標或者引用來說,若是只是拷貝表面,那麼拷貝後的物體的指標也和原來的指標指向的是同乙個物件,所以雖然目的想完成乙個完美的轉殖體,但是卻發現轉殖體和原來的物體中間還有一根線連著,沒有完美的分離。

int

*p = new int(47);

int*q = p;

如q與p都是指向乙個物體一樣。那麼如果原來的物體銷毀了,但是現在拷貝的物體還在,那麼這時候你拷貝後的物體的成員指標就是乙個懸掛指標,指向了不再存在的物體,那麼你訪問的話,那就不知道會發生什麼了。而對於深拷貝,這乙個勤奮的人,他不會只做表面,他會把每乙個細節都照顧好。於是,當他遇到指標的時候,他會知道new出來一塊新的記憶體,然後把原來指標指向的值拿過來,這樣才是真正的完成了轉殖體和原來的物體的完美分離,如果物體比作人的話,那麼原來的人的每一根毛細血管都被完美的拷貝了過來,而絕非只是表面。所以,這樣的代價會比淺拷貝耗費的精力更大,付出的努力更多,但是是值得的。當原來的物體銷毀後,轉殖體也可以活的很好。然而事實上是這個世界上大多都是懶漢,包括程式設計的人,編譯器等,所以預設的行為都是淺拷貝,於是有時候你需要做乙個勤奮的人,讓事情做正確,自己去完成深拷貝所需要的事情。

C 深拷貝 與 淺拷貝

最近在寫一些c 程式,遇到個問題,記憶體會出錯,查了一些材料,終於發現問題所在了,原來碰到了傳說中的深拷貝和淺拷貝問題了,檢視一些材料,現在對這個問題做個總結 在類定義中,預設是淺拷貝,即 位拷貝 用在基本類中或者一些沒有指標的自定義型別中沒有一點問題,但是當遇到含有指標變數的自定義型別的時候,就會...

C 淺拷貝與深拷貝

淺拷貝 shallow copy 指的是當物件的字段被拷貝的時候,字段應用的物件不會被拷貝。深拷貝是對物件例項當中的字段引用的物件也進行拷貝的一種方式。淺拷貝可以通過將類實現介面icloneable class myclass icloneable 舉個簡單的例項 using system usin...

c 深拷貝與淺拷貝

對於普通型別的物件來說,它們之間的複製是很簡單的,例如 int a 88 int b a 而類物件與普通物件不同,類物件內部結構一般較為複雜,存在各種成員變數。下面看乙個類物件拷貝的簡單例子。iostream using namespace std class cexample void show ...