我們有時候會聽說c++中有深拷貝和淺拷貝的說法,那麼深拷貝和淺拷貝的區別是什麼呢?簡單來說,淺拷貝就是簡單的賦值拷貝操作;而深拷貝是程式設計師手動在堆區重新申請一塊記憶體然後進行拷貝操作,那麼這麼做的意義何在呢,請看下面的乙個場景,
#include
#include
using
namespace std;
class
student};
intmain()
建立student學生類,在其中自定義乙個有參建構函式,在堆區手動new申請一塊記憶體使用乙個int型別的指標接收建立例項物件時傳入的學生年齡,這裡隱式呼叫了編譯器預設的拷貝建構函式來建立物件s2:
student
(const student& s)
//(偽**)編譯器預設的拷貝建構函式
執行結果如下:
看起來執行結果是沒什麼問題,在程式執行結束後由預設析構函式來自動釋放**棧區記憶體(這裡沒有顯示);但是我們說,在堆區手動開闢的記憶體也要由程式設計師手動釋放,這一點尤其是對執行大型的複雜程式很有必要,所以我們嘗試在上面的student類中過載析構函式來手動釋放堆區的記憶體:
~
student()
//析構函式宣告
}
然而函式執行結束呼叫析構函式時程式崩了,這是因為在呼叫預設拷貝建構函式建立物件s2時是淺拷貝,僅僅是將指標s1.m_age的值拷貝給了s2.m_age,此時s1.m_age和s2.m_age都指向同一塊記憶體空間(即儲存s1.m_age的那塊堆區的記憶體位址),程式執行結束呼叫析構函式時,根據先進後出的原則,他們指向的那塊堆區記憶體首先被s2的析構函式釋放掉,隨後當s1的析構函式也來試圖釋放這塊記憶體時就會出錯,因為那塊空間此時已經被s2的析構函式釋放掉了,所以淺拷貝帶來的問題:堆區記憶體的重複釋放。
解決方法也很簡單,在student類中過載拷貝建構函式,在給新物件賦值同時new手動申請一塊新的記憶體空間即可:
#include
#include
using
namespace std;
class
student
student
(const student& s)
//過載後的拷貝建構函式
~student()
//析構函式宣告}}
;int
main()
在呼叫拷貝建構函式建立物件s2時是深拷貝,在用一塊新的儲存空間來儲存指標s1.m_age指向的那塊記憶體的值,物件s1.m_age和s2.m_age分別指向一塊不同的堆區記憶體,所以在呼叫各自的析構函式釋放記憶體時互不影響。
總結:淺拷貝只是簡單的賦值拷貝操作,若在類中有在堆區開闢的屬性,一定要自己過載拷貝建構函式進行深拷貝,防止淺拷貝帶來的堆區記憶體重複釋放的問題。
C 淺拷貝和深拷貝
class test test const test t val new int t.val test private int val 現在定義兩個物件,test t1 9 test t2 t1 如果你不提供copy建構函式 注釋掉的那個 那麼t1和t2的成員 val指向同乙個物件,當析構的時候,同...
c 深拷貝和淺拷貝
深拷貝和淺拷貝 ca const ca c 就是我們自定義的拷貝建構函式。可見,拷貝建構函式是一種特別的建構函式,函式的名稱必須和類名稱一致,他的唯一的乙個引數是本型別的乙個引用變數,該引數是const型別,不可變的。例如 類x的拷貝建構函式的形式為x x x 當用乙個已初始化過了的自定義類型別物件...
c 深拷貝和淺拷貝
對於普通型別的物件來說,它們之間的複製是很簡單的,例如 int a 88 int b a 而類物件與普通物件不同,類物件內部結構一般較為複雜,存在各種成員變數。下面看乙個類物件拷貝的簡單例子。iostream using namespace std class cexample void show ...