c++深淺拷貝
淺拷貝:也就是在物件複製時,只是對物件中的資料成員進行簡單的賦值,如果物件中存在動態成員,即指標,淺拷貝就會出現問題。
深拷貝:對於深拷貝,針對成員變數存在指標的情況,不僅僅是簡單的指標賦值,而是重新分配記憶體空間。
在定義一個類的時候由於沒有自定義拷貝建構函式,C++編譯器自動會產生一個預設的拷貝建構函式。這個預設的拷貝建構函式採用的是“位拷貝”(淺拷貝),而非“值拷貝”(深拷貝)的方式,如果類中含有指標變數,預設的拷貝建構函式必定出錯。
用一句簡單的話來說就是淺拷貝只是對指標的拷貝,拷貝後兩個指標指向同一個記憶體空間,深拷貝不但對指標進行拷貝,而且對指標指向的內容進行拷貝,經深拷貝後的指標是指向兩個不同地址的指標。
#include<iostream> using namespace std; class Test{ public: Test(int a = 5) { m_a = a; m_p = new int[m_a]; } //自定義深拷貝 Test(const Test& t) { m_a = t.m_a; m_p = new int; } //預設拷貝(淺拷貝) /*Test(const Test& t) { m_a = t.m_a; m_p = t.m_p; }*/ ~Test() { delete m_p; cout << "析構" << endl; } void print() { printf("%d %d\n", m_a, m_p); } private: int m_a; int *m_p; }; int main() { Test t; t.print(); Test t_copy = t; t_copy.print(); system("pause"); }
假如有一個成員變數的指標,int m_p;
其一,淺拷貝只是拷貝了指標,使得兩個指標指向同一個地址,這樣在物件塊結束,呼叫函式析構的時,會造成同一份資源析構2次,即delete同一塊記憶體2次,造成程式崩潰。
其二,淺拷貝使得t.m_p和t_copy.m_p指向同一塊記憶體,任何一方的變動都會影響到另一方。
其三,在釋放記憶體的時候,會造成t.m_p原有的記憶體沒有被釋放,造成記憶體洩露。
//自定義深拷貝 Test(const Test& t) { m_a = t.m_a; m_p = new int; } //預設拷貝(淺拷貝) Test(const Test& t) { m_a = t.m_a; m_p = t.m_p; }
觀察上面的程式碼,深拷貝和淺拷貝主要的處理就在於指標,深拷貝會重新為物件裡面的指標變數分配一塊指向的空間,而淺拷貝則僅僅簡單的將一個物件的成員變數賦值給另一個物件的成員變數。
深拷貝採用了在堆記憶體中申請新的空間來儲存資料,這樣每個可以避免指標懸掛。
可以看到在拷貝建構函式中為成員變數申請了新的記憶體空間,這就使得兩個物件的成員變數不指向同一個記憶體空間,除非你的確需要這樣做,用於實現一些其他的用途。