C++之拷貝構造函數的淺copy和深copy


1、深拷貝和淺拷貝構造函數總結:ios

一、兩個特殊的構造函數:web

(1)無參構造函數:微信

沒有參數的構造函數網絡

Class Test
{
 public:
     Test()
     {
       //這是一個無參構造函數
     }
};

當類中沒有定義構造函數時,編譯器默認提供一個無參構造函數,而且其函數體爲空;換句話來講,就是咱們在類中,不用咱們程序猿本身寫,編譯就自動提供了無參構造函數(只是咱們肉眼看不到!)編輯器

#include <iostream>
#include <string>

class Test{

//編譯器默認給咱們提供了一個無參構造函數,只是咱們肉眼看不到

};



int main()
{
   Test t;

  return 0;
}

結果輸出(編譯時可以經過的):ide

root@txp-virtual-machine:/home/txp# g++ test.cpp
root@txp-virtual-machine:/home/txp


(2)拷貝構造函數:函數

參數爲const class_name&的構造函數flex

class Test{
public:
   Test(const Test& p)
   {
       
    
   }
}

當類中沒有定義拷貝構造函數時,編譯器默認提供了一個拷貝構造函數,簡單的進行成員變量的值賦值ui

#include <iostream>
#include <string>

class Test{

private:
   int i;
   int j;
public:
 /*  Test(const Test& p)編譯器默認提供這樣操做的
   {
      i = p.i;
      j = p.j; 
   }*/


};



int main()
{
   Test t;



  return 0;
}

輸出結果(編譯能夠經過):url

root@txp-virtual-machine:/home/txp# g++ test.cpp
root@txp-virtual-machine:/home/txp

(3)注意:

在寫程序的時候,定義的類對象初始化時看屬於哪一種類型的:

Test t;//對應無參構造函數

Test t(1);//對應有參構造函數

Test t1;
Test t2=t1;//對應拷貝構造函數

好比下面我定義的類對象屬於無參構造函數(固然前提是你手寫了其餘構造函數,雖說編譯器會默認提供,可是既然要手寫,那麼三種構造函數就在定義類對象的時候按需求來寫),若是隻寫了有參數構造函數,那麼編譯器就會報錯:

#include <iostream>
#include <string>

class Test{

private:
   int i;
   int j;
public:
  Test(int a)
  {
     i = 9;
     j=8;
  }
  Test(const Test& p)
   {
      i = p.i;
      j = p.j;
   }


};
int main()
{
   Test t;
  return 0;
}


輸出結果:

root@txp-virtual-machine:/home/txp# g++ test.cpp
test.cpp: In function ‘int main()’:
test.cpp:25:9: error: no matching function for call to ‘Test::Test()’
    Test t;
         ^
test.cpp:25:9: note: candidates are:
test.cpp:15:3: note: Test::Test(const Test&)
   Test(const Test& p)
   ^
test.cpp:15:3: note:   candidate expects 1 argument, 0 provided
test.cpp:10:3: note: Test::Test(int)
   Test(int a)
   ^
test.cpp:10:3: note:   candidate expects 1 argument, 0 provided

四、拷貝構造函數的意義:

(1)淺拷貝

拷貝後對象的物理狀態相同

(2)深拷貝

拷貝後對象的邏輯狀態相同

(3)編譯器提供的拷貝構造函數只進行淺拷貝

代碼版本一:

#include <stdio.h>
#include <string>

class Test{
private:
   int i;
   int j;
   int *p;
public:
   int getI()
   {
      return i;
   }
   int getJ()
   {
      return j;
   }
   int *getP()
   {
      return p;
   }
   Test(int a)
   {
      i = 2;
      j = 3;
      p = new int;
      *p = a;
  }
  void free()
  {

    delete p;
  }
};
int main()
{
   Test t1(3);//Test t1 3;
   Test t2 = t1;

  printf("t1.i = %d, t1.j = %d, t1.p = %p\n", t1.getI(), t1.getJ(), t1.getP());
  printf("t2.i = %d, t2.j = %d, t2.p = %p\n", t2.getI(), t2.getJ(), t2.getP());

   t1.free();
   t2.free();
   
   return 0;
}

輸出結果:

root@txp-virtual-machine:/home/txp# g++ test.cpp
root@txp-virtual-machine:/home/txp# ./a.out
t1.i = 2, t1.j = 3, t1.p = 0x1528010
t2.i = 2, t2.j = 3, t2.p = 0x1528010
*** Error in `./a.out': double free or corruption (fasttop): 0x0000000001528010 ***
Aborted (core dumped)

註解:出現了段錯誤,仔細分析,咱們發現這裏釋放了堆空間兩次(由於咱們這裏沒有調用拷貝構造函數,也就是本身去寫拷貝構造函數;因此這種狀況是淺拷貝,不能釋放兩次堆空間):

代碼版本二(加上拷貝構造函數):

#include <stdio.h>
#include <string>

class Test{
private:
   int i;
   int j;
   int *p;
public:
   int getI()
   {
      return i;
   }
   int getJ()
   {
      return j;
   }
   int *getP()
   {
      return p;
   }
   Test(int a)
   {
      i = 2;
      j = 3;
      p = new int;
      *p = a;
  }
  Test(const Test& t)
  {
    i = t.i;
    j = t.j;
    p = new int;

    *p = *t.p;
  }

  void free()
  {

    delete p;
  }
};
int main()
{
   Test t1(4);
   Test t2 = t1;

   printf("t1.i = %d, t1.j = %d, t1.p = %p\n", t1.getI(), t1.getJ(), t1.getP());
   printf("t2.i = %d, t2.j = %d, t2.p = %p\n", t2.getI(), t2.getJ(), t2.getP());
   t1.free();
   t2.free();

   return 0;
}

輸出結果:

root@txp-virtual-machine:/home/txp# g++ test.cpp
root@txp-virtual-machine:/home/txp# ./a.out
t1.i = 2, t1.j = 3, t1.p = 0xb0a010
t2.i = 2, t2.j = 3, t2.p = 0xb0a030

註解:從打印的p地址空間來看,就知釋放的兩個對象的堆空間不一樣,再也不是指向同一堆空間了;同時咱們發現淺拷貝只是簡單數值上的進行賦值而已;深拷貝不僅是簡單的值賦值,而是從內存的角度來看,是操做不一樣的內存。

五、何時須要進行深拷貝?

(1)對象中有成員指代了系統中的資源

  • 成員指向了動態內存空間

  • 成員打開了外存中的文件

  • 成員使用了系統中的網絡端口

注意:通常來講,自定義拷貝構造函數(也就是咱們本身手寫的),必然須要實現深拷貝!

2、總結:

  • C++編譯器會默認提供構造函數

  • 無參構造函數用於定義對象的默認初始化狀態

  • 拷貝構造函數在建立對象時拷貝對象的狀態

  • 對象的拷貝有淺拷貝和深拷貝兩種方式。

好了,今天的分享就到這裏,若是文章中有錯誤或者不理解的地方,能夠交流互動,一塊兒進步。我是txp,下期見!

本文分享自微信公衆號 - TXP嵌入式(txp1121518wo-)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索