C++_深淺拷貝
一、何時呼叫拷貝建構函式
1、物件在建立時使用其他的物件初始化
Person p(q); //此時複製建構函式被用來建立例項p
Person p = q; //此時複製建構函式被用來在定義例項p時初始化p
2、物件作為函式的引數進行值傳遞時
f(p); //此時p作為函式的引數進行值傳遞,p入棧時會呼叫複製建構函式建立一個區域性物件,與函式內的區域性變數具有相同的作用域。
注意:需要注意的是,賦值並不會呼叫複製建構函式,賦值只是賦值運算子(過載)在起作用
p = q; //此時沒有複製建構函式的呼叫! (記住初始化和賦值的區別)
簡單來記的話就是,如果物件在宣告的同時將另一個已存在的物件賦給它,就會呼叫複製建構函式;如果物件已經存在, 然後將另一個已存在的物件賦給它,呼叫的就是賦值運算子(過載)
二、解析
1.在未定義顯示拷貝建構函式的情況下,系統會呼叫預設的拷貝函式–即淺拷貝,它能夠完成成員的一對一拷貝(逐位複製),當類中資料成員沒有指標時,利用淺拷貝完全沒問題的;但當資料成員中有指標時,如果採用簡單的淺拷貝,那麼兩個類中的兩個指標將會指向同一塊地址,當物件快結束時,會呼叫兩次析構器,從而導致指標懸掛現象,所以此時必須使用深拷貝
2.簡單來說,帶指標用深拷貝,不帶指標用淺拷貝
1.無指標的淺拷貝
class A { public: A(int _data):data(_data){} A(){} private: int data; }; int main() { A a(5); A b=a;//淺拷貝 } //解釋:b=a;就是淺拷貝,執行完b.data=5;如果物件中沒有其他資源(如:堆,檔案,系統資源),深淺無差。
2.有指標的淺拷貝(導致記憶體洩露)
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(5); A b=a; }
這裡b=a會造成未定義行為,因為類A中拷貝構造器是編譯器生成的,所以b=a執行的是淺拷貝(記住:淺拷貝是物件資料之間的簡單賦值)例如:b.size=a.size和b.data=a.data
這裡b的指標data和a的指標指向了堆上的同一塊記憶體,a和b析構時同一塊記憶體將會被釋放兩次,其結果是,有未定義的記憶體將會被洩露或程式奔潰!!!
3.有指標的深拷貝,(解決上面的問題)物件另開闢一塊記憶體
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(5);
A b=a;
}
以上程式碼就沒有問題了,與淺拷貝區別就是,在自己定義的拷貝函式裡另開闢一塊記憶體即深拷貝。
轉載https://blog.csdn.net/w_linux/article/details/65450857