1. 程式人生 > >C++ 拷貝建構函式中淺拷貝與深拷貝

C++ 拷貝建構函式中淺拷貝與深拷貝

淺拷貝建構函式
看一段拷貝建構函式的程式碼

#include <iostream>
#include <cstring>
using namespace std;
class Array{
public :
    Array(){
        cout<<"Array()"<<endl;
    }
    Array(const Array &arr){ /// 拷貝建構函式
        m_iCount = arr.m_iCount;
        cout<<"Array &"<<endl;
    }

    virtual
~Array(){ cout<<"~Array()"<<endl; } void setCount(int _count){ m_iCount = _count; } int getCount(){ return m_iCount; } private : int m_iCount; }; int main(){ Array arr1; arr1.setCount(5); Array arr2(arr1);///淺拷貝 cout<<"arr2 m_iCount "
<<arr2.getCount()<<endl; return 0; }

類Array例項化一個arr1的物件,並給資料成員m_iCount賦值為5。
接著類Array例項化一個物件arr2並將arr1的資料成員的值拷貝給arr2
執行程式碼,顯然arr1和arr2的資料成員m_iCount的值都為5,系統給arr1,arr2分配了記憶體空間並使得arr1的值複製給了arr2
接下來再看一段程式碼:

#include <iostream>
#include <cstring>
using namespace std;
class
Array{ public : Array(int _count){ m_iCount = _count; m_pArr = new int[m_iCount]; cout<<"Array()"<<endl; } Array(const Array &arr){ /// 拷貝建構函式 m_iCount = arr.m_iCount; m_pArr = arr.m_pArr; ///兩個指標指向同一塊記憶體 cout<<"Array &"<<endl; } virtual ~Array(){ delete []m_pArr; m_pArr = NULL; cout<<"~Array()"<<endl; } void setCount(int _count){ m_iCount = _count; } int getCount(){ return m_iCount; } void printAddr(){ cout<<"m_pArr : "<<m_pArr<<endl; } private : int m_iCount; int *m_pArr; }; int main(){ Array arr1(5); Array arr2(arr1); arr1.printAddr(); arr2.printAddr(); return 0; }

我們在類中新增一個數據成員int型的指標m_pArr,例項化一個物件arr1並給資料成員m_iCount賦值為5,與此同時系統也需要給另一個數據成員m_pArr在堆區分配記憶體空間
接著例項化一個物件arr2並將arr1的值複製給arr2,系統呼叫拷貝建構函式。將arr1.m_iCount賦值給arr2.m_iCount,將arr1.m_pArr賦值給arr2.m_iArr。因為在拷貝建構函式中,系統並沒有在堆區分配一個記憶體空間給arr2的資料成員m_iArr。所以這裡兩個物件的資料成員m_iArr顯然都指向了同一塊記憶體空間,那麼會有什麼問題呢?
當我們在呼叫解構函式,釋放記憶體空間的時候,兩個物件指向的那塊記憶體空間就會被釋放兩次,這樣程式會奔潰,導致出錯。
這就是淺拷貝帶來的危險
這裡再引入深拷貝:

Array(const Array &arr){ /// 拷貝建構函式
      m_iCount = arr.m_iCount;
      m_pArr = new int[m_iCount];
      for(int i=0;i<m_iCount;i++) m_pArr[i]=arr.m_pArr[i];
        cout<<"Array &"<<endl;
    }

當類中存在資料成員需要動態開闢記憶體空間的時候,需要使用深拷貝的方式

區別:
在某些狀況下,類內成員變數需要動態開闢堆記憶體,如果實行位拷貝,也就是把物件裡的值完全複製給另一個物件,如A=B。這時,如果B中有一個成員變數指標已經申請了記憶體,那A中的那個成員變數也指向同一塊記憶體。這就出現了問題:當B把記憶體釋放了(如:析構),這時A內的指標就是野指標了,出現執行錯誤。

  深拷貝和淺拷貝可以簡單理解為:如果一個類擁有資源,當這個類的物件發生複製過程的時候,資源重新分配,這個過程就是深拷貝,反之,沒有重新分配資源,就是淺拷貝。