- 差別
- 在未定義顯示拷貝構造函數的情況下,系統會調用預設的拷貝函數——即淺拷貝,它能夠完成成員的一對一拷貝(逐位複制),當類中資料成員沒有指針時,利用淺拷貝完全沒有問題;但當資料成員中有指針時,如果采用簡單的淺拷貝,那麼兩個類中的兩個指針将會指向同一塊位址,當對象快結束時,會調用兩次析構器,進而導緻指針懸挂現象,是以此時必須使用深拷貝
- 簡單來說,帶指針用深拷貝,不帶指針用淺拷貝
- 具體解釋
-
無指針的淺拷貝
x ———-> x
p ———-> p
-
有指針的淺拷貝
x ———–> x
*p ———–> *p
\ /
\ /
\ /
記憶體
-
有指針的深拷貝
x ————> x
*p ————> *p
| |
| |
記憶體 記憶體
-
- 用代碼解釋深淺拷貝
- 無指針的淺拷貝
class A { public: A(int _data):data(_data){} A(){} private: int data; }; int main() { A a(); A b = a; //淺拷貝 } //解釋:b = a;就是淺拷貝,執行完b.data = 5;如果對象中沒有其他資源(如:堆,檔案,系統資源),則深淺無差。
- 有指針的淺拷貝(導緻記憶體洩漏)
class A { public: A(int _size):size(_size) { data = new int[size]; }//給data配置設定size個記憶體 A(){} ~A() { delete []data; } private: int *data; int size; }; int main() { A a(); A b = a; } //這裡b = a會造成未定義行為,因為類A中拷貝構造器是編譯器生成的,是以b=a執行的是淺拷貝。 //這裡b的指針data和a的指針指向了堆上的同一塊記憶體,a和b析構時同一塊記憶體将會被釋放兩次其結果是,有未定義的記憶體将會被洩漏或程式崩潰
- 有指針的深拷貝
class A { public: A(int _size):size(_size) { data = new int[size]; }//給data配置設定size個記憶體 A(){} A(const A&_A):size(_A.size) { data = new int[size]; }//深拷貝 ~A() { delete []data; } private: int *data; int size; }; int main() { A a(); A b = a; }
- 無指針的淺拷貝