【淺拷貝】就是對象的數據成員之間的簡單賦值。如你設計了一個類而沒有提供它的復制構造函數,當用該類的一個對象去給另一個對象賦值時所執行的過程就是淺拷貝,如:
class A { public: A(int _data): data(_data){} A() {}
private: int data; }; int main() { A a(5), b = a; // 僅僅是數據成員之間的賦值 }
這一句b = a;就是淺拷貝,執行完這句后b.data = 5;
如果對象中沒有其他的資源(如:堆,文件,系統資源等),則深拷貝和淺拷貝沒有什么區別,但當對象中有這些資源時,例子:
class A { public: A(int _size) : size(_size) { data = new int[size]; // 假如其中有一段動態分配的內存 } A(){}; ~A() { delete [] data; // 析構時釋放資源 }
private: int* data; int size; }; int main() { A a(5), b = a; // 注意這一句 }
這里的b = a會造成未定義行為,因為類A中的復制構造函數是編譯器生成的,所以b = a執行的是一個淺拷貝過程。我說過淺拷貝是對象數據之間的簡單賦值,比如:
b.size = a.size;b.data = a.data;這里b的指針data和a的指針指向了堆上的同一塊內存,a和b析構時,b先把其data指向的動態分配的內存釋放了一次,而后a析構時又將這塊已經被釋放過的內存再釋放一次。對同一塊動態內存執行2次以上釋放的結果是未定義的,所以這將導致內存泄露或程序崩潰。
所以這里就需要深拷貝來解決這個問題,【深拷貝】指的就是當拷貝對象中有對其他資源(如堆、文件、系統等)的引用時(引用可以是指針或引用)時,對象的另開辟一塊新的資源,而不再對拷貝對象中有對其他資源的引用的指針或引用進行單純的賦值。如:
class A { public: A(int _size) : size(_size) { data = new int[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(5), b = a; // 這次就沒問題了 }
總結:
深拷貝和淺拷貝的區別是在對象狀態中包含其它對象的引用的時候,當拷貝一個對象時,如果需要拷貝這個對象引用的對象,則是深拷貝,否則是淺拷貝。
