深拷貝與淺拷貝
阿新 • • 發佈:2021-01-20
深拷貝與淺拷貝的區別
深拷貝和淺拷貝本質的區別在於淺拷貝獲取的是原物件的引用,深拷貝獲取的是原物件的複製實體。
淺拷貝:簡單的賦值拷貝操作
深拷貝:在堆區重新申請空間,進行拷貝操作
為什麼要使用深拷貝
C++編譯器預設的拷貝建構函式都是淺拷貝。淺拷貝在類中存在指標的時候,拷貝的是原物件的引用,這會帶來一個問題:
在物件退出的時候,會呼叫解構函式對申請的堆記憶體進行釋放,如果是預設的淺拷貝,兩次解構函式會對同一個空間進行釋放,這會報錯。
為了避免淺拷貝的這個問題,必須使用深拷貝:拷貝建構函式重新申請一個記憶體空間,複製原物件。這樣釋放的時候就可以都釋放了。
例項
class Person {
public:
Person():age(10)
{
cout << "person的無參建構函式" << endl;
}
Person(int a, int height) {
age = a;
m_height = new int(height);
cout << "Person的有參建構函式" << endl;
}
//拷貝建構函式
Person(const Person &p) {
age = p.age;
//深拷貝:重新申請一個堆,內容複製原物件
m_height = new int(*p.m_height);
cout << "Person的拷貝建構函式" << endl;
}
//解構函式
~Person() {
cout << "person的解構函式" << endl;
//對申請的堆進行釋放
if (m_height != NULL) {
delete m_height;
m_height = NULL;
}
}
int age;
int *m_height;
};
//--------------深拷貝與淺拷貝----------------
void test1() {
Person p1(16, 180);
cout << "年齡為:" << p1.age << "\t身高為:" << *p1.m_height << "\t地址為:" << (int*)&p1.m_height << endl;
Person p2(p1);
cout << "年齡為:" << p2.age << "\t身高為:" << *p2.m_height << "\t地址為:" << (int*)&p2.m_height << endl;
}
這裡的拷貝建構函式Person(const Person &p)
需要我們自己定義成深拷貝形式(C++編譯器預設的是淺拷貝:m_height = p.m_height;
)。
如果是淺拷貝,test1()在拷貝構造p2的時候,會直接把p2.m_height = p1.m_height
,p1,p2指向了同一個堆的區域。在test1()結束後,會先呼叫p1的解構函式,把堆中的空間釋放掉;然後呼叫p2的解構函式,又想去釋放這個已經釋放的空間,這就會出錯。
這就需要改為深拷貝,new int(*p.m_height)
,重新在堆中申請一塊和原物件一模一樣的空間,這樣兩次解構函式就會分別去釋放p1,p2申請的空間,就不會出錯了。
可以看到結果,p1,p2申請的m_height的堆空間不同,就可以分別呼叫析構函數了。