C 的淺拷貝出現的錯誤

2021-07-15 21:52:33 字數 1148 閱讀 3503

之前看一些資料提到淺拷貝的問題,即在複製物件時,只是對物件中的資料成員進行簡單的賦值,預設拷貝建構函式執行的也是淺拷貝。如果物件中存在動態成員,如指標,那麼僅僅做淺拷貝是不夠的,並且容易引發錯誤,最經典的例子:

#include 

#include

using

namespace

std;

class a;

~a();

int* m_p;

};void copytest(a atmp)

int main()

執行這段**會出現崩潰,因為析構函式裡的delete m_p執行了兩次,而m_p指向的是同一塊記憶體。因為在呼叫copytest時傳入了物件a,atmp利用a作為引數執行了預設拷貝建構函式,但是只是簡單地把物件a的m_p的記憶體位址拷貝給atmp的m_p,因此這個時候atmp.m_p只是指向了和a.m_p相同的記憶體塊。

當copytest執行完畢後,臨時變數atmp會被銷毀,這個時候析構函式被呼叫,delete了m_p指向的記憶體。而當main函式執行完畢後,a物件也需要被銷毀,這個時候析構函式再次被執行,而這個時候m_p已經不知道指向什麼地方了,delete操作引發程式崩潰。

解決這個問題的方法有很多:一種方法是實現智慧型指標,對m_p進行引用計數,當引用值為0時才執行delete;也可以每次把m_p的初始值設為null,每次執行delete操作前先檢查m_p是否為null,delete後再讓m_p指向null,這個方法其實道理和智慧型指標差不多,只是智慧型指標更合理有效地利用類進行管理;還有一種做法是重寫拷貝建構函式,確保在物件複製時進行深拷貝,即重新分配記憶體空間,並且把a中m_p指向記憶體的內容拷貝到分配的空間。

以上這種情況只有在利用「值傳遞」複製物件時才發生,如果我們傳遞的是指標,就不會有這種情況了:

#include 

#include

using

namespace

std;

class a;

~a();

int* m_p;

};void copytest(a* atmp)

int main()

因為傳遞到copytest的引數只是乙個位址,指向的還是物件a,並沒有發生物件的複製,當然就不存在上面的深淺拷貝問題了。

c 的深拷貝與淺拷貝

所謂淺拷貝,指的是在物件複製時,只是對物件中的資料成員進行簡單的賦值,上面的例子都是屬於淺拷貝的情況,預設拷貝建構函式執行的也是淺拷貝。大多情況下 淺拷貝 已經能很好地工作了,但是一旦物件存在了動態成員,那麼淺拷貝就會出問題了,讓我們考慮如下一段 class rect public rect 建構函...

C 的深拷貝與淺拷貝

當用乙個已初始化過了的自定義類型別物件去初始化另乙個新構造的物件的時候,拷貝建構函式就會被自動呼叫。也就是說,當類的物件需要拷貝時,拷貝建構函式將會被呼叫。以下情況都會呼叫拷貝建構函式 1 乙個物件以值傳遞的方式傳入函式體 2 乙個物件以值傳遞的方式從函式返回 3 乙個物件需要通過另外乙個物件進行初...

C 的深拷貝與淺拷貝

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