最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++淺拷貝與深拷貝及引用計數(shù)分析

 更新時間:2017年06月09日 10:17:25   作者:aidear_evo  
這篇文章主要介紹了C++淺拷貝與深拷貝及引用計數(shù)分析的相關(guān)資料,需要的朋友可以參考下

C++淺拷貝與深拷貝及引用計數(shù)分析

在C++開發(fā)中,經(jīng)常遇到的一個問題就是與指針相關(guān)的內(nèi)存管理問題,稍有不慎,就會造成內(nèi)存泄露、內(nèi)存破壞等嚴重的問題。不像Java一樣,沒有指針這個概念,所以也就不必擔心與指針相關(guān)的一系列問題,但C++不同,從C語言沿襲下來的指針是其一大特點,我們常常要使用new/delete來動態(tài)管理內(nèi)存,那么問題來了,特別是伴隨著C++的繼承機制,如野指針、無效指針使用、內(nèi)存泄露、double free、堆碎片等等,這些問題就像地雷一樣,一不小心就會踩那么幾顆。

先來談一下C++類中常見的淺拷貝問題,以及由此引發(fā)的double free。什么是淺拷貝?當類中的成員變量包括指針時,而又沒有定義自己的拷貝構(gòu)造函數(shù),那么在拷貝一個對象的情況下,就會調(diào)用其默認拷貝構(gòu)造函數(shù),其實這個函數(shù)沒做什么事,只是對其成員變量作了個簡單的拷貝,也就是所謂的位拷貝,它們指向的還是同一個存儲空間,當對象析構(gòu)時,就會析構(gòu)多次,也就是double free,下面舉例說明。

class Common
{
public:
  Common()
  {
    std::cout << "Common::Common" << std::endl;
  }

  Common(const Common &r)
  {
    std::cout << "Common::Common copy-constructor" << std::endl;
  }

  ~Common()
  {
    std::cout << "Common::~Common" << std::endl;
  }
};

類Common是個一般的類,定義了構(gòu)造、拷貝構(gòu)造和析構(gòu)函數(shù),在函數(shù)里輸出一些log,用以跟蹤函數(shù)調(diào)用情況。

class BitCopy
{
public:
  BitCopy()
    : m_p(new Common)
  {
    std::cout << "BitCopy::BitCopy" << std::endl;
  }

  ~BitCopy()
  {
    std::cout << "BitCopy::~BitCopy" << std::endl;
    if (m_p) {
      delete m_p;
      m_p = NULL;
    }
  }

private:
  Common *m_p;
};

類BitCopy就是一個淺拷貝類,成員變量是我們剛定義的類指針,構(gòu)造函數(shù)實例化成員變量,析構(gòu)函數(shù)delete成員變量,沒有定義拷貝構(gòu)造函數(shù)。

int main()
{
  BitCopy a;
  BitCopy b(a);
  return 0;
}
log如下:
Common::Common
BitCopy::BitCopy
BitCopy::~BitCopy
Common::~Common
BitCopy::~BitCopy
Common::~Common
*** Error in `./a.out': double free or corruption (fasttop): 0x0000000001f4e010 ***
已放棄 (核心已轉(zhuǎn)儲)

從上面的log可以看出,對象a調(diào)用了構(gòu)造函數(shù),對象b調(diào)用的是默認拷貝構(gòu)造函數(shù),最后析構(gòu)了兩次,從而造成double free,核心已轉(zhuǎn)儲即core dump。

針對以上問題,該怎么解決呢?有兩個辦法,一個是深拷貝,一個是引用計數(shù)。先來看一下深拷貝,深拷貝要定義自己的拷貝構(gòu)造函數(shù),在函數(shù)中給成員變量重新分配存儲空間,也就是所謂的值拷貝,這樣它們所指向的就是不同的存儲空間,析構(gòu)時不會有問題,但這種方法只適用于較小的數(shù)據(jù)結(jié)構(gòu),如果數(shù)據(jù)結(jié)構(gòu)過大,多次分配存儲空間之后,剩余的存儲空間將逐漸減小,

下面看個例子。

class ValueCopy
{
public:
  ValueCopy()
    : m_p(new Common)
  {
    std::cout << "ValueCopy::ValueCopy" << std::endl;
  }

  ValueCopy(const ValueCopy &r)
    : m_p(new Common(*r.m_p))
  {
    std::cout << "ValueCopy::ValueCopy copy-constructor" << std::endl;
  }

  ~ValueCopy()
  {
    std::cout << "ValueCopy::~ValueCopy" << std::endl;
    if (m_p) {
      delete m_p;
      m_p = NULL;
    }
  }

private:
  Common *m_p;
};

類ValueCopy是個深拷貝類,與上面例子的淺拷貝類不同的是定義了拷貝構(gòu)造函數(shù),在函數(shù)中給成員變量重新分配存儲空間,下面是用法及l(fā)og。

int main()
{
  ValueCopy c;
  ValueCopy d(c);
  return 0;
}
Common::Common
ValueCopy::ValueCopy
Common::Common copy-constructor
ValueCopy::ValueCopy copy-constructor
ValueCopy::~ValueCopy
Common::~Common
ValueCopy::~ValueCopy
Common::~Common

從上面的log可以看出,對象c調(diào)用了構(gòu)造函數(shù),對象d調(diào)用的是自定義拷貝構(gòu)造函數(shù),最后析構(gòu)了兩次而沒有問題,可見深拷貝的用處所在。

引用計數(shù)與深拷貝不同,方法是共享同一塊存儲空間,這個對大的數(shù)據(jù)結(jié)構(gòu)比較有利。使用引用計數(shù),需要在類中定義一個成員變量專門用于計數(shù),初始值為1,后面引用了這個對象就加1,對象銷毀時引用減1,但并不真正的delete這個對象,只有當這個成員變量的值為0時才進行delete,例子如下。

class A
{
public:
  A()
    : m_refCount(1)
  {
    std::cout << "A::A" << std::endl;
  }

  A(const A &r)
    : m_refCount(1)
  {
    std::cout << "A::A copy-constructor" << std::endl;
  }

  ~A()
  {
    std::cout << "A::~A" << std::endl;
  }

  void attach()
  {
    std::cout << "A::attach" << std::endl;
    ++m_refCount;
  }

  void detach()
  {
    if (m_refCount != 0) {
      std::cout << "A::detach " << m_refCount << std::endl;
      if (--m_refCount == 0) {
        delete this;
      }
    }
  }

private:
  int m_refCount;
};

class B
{
public:
  B()
    : m_pA(new A)
  {
    std::cout << "B::B" << std::endl;
  }

  B(const B &r)
    : m_pA(r.m_pA)
  {
    std::cout << "B::B copy-constructor" << std::endl;
    m_pA->attach();
  }

  ~B()
  {
    std::cout << "B::~B" << std::endl;
    m_pA->detach();
  }

private:
  A* m_pA;
};

類A用到了引用計數(shù),構(gòu)造和拷貝構(gòu)造函數(shù)都初始化為1,attach()函數(shù)為引用加1,detach()函數(shù)為引用減1,當引用計數(shù)值為0時delete對象。類B中的成員變量有個指針指向A,拷貝構(gòu)造函數(shù)中調(diào)用了attach(),析構(gòu)函數(shù)中調(diào)用了detach(),這樣也是一種保護,不會有內(nèi)存泄露,也不會有double free,log如下。

int main()
{
  B e;
  B f(e);
  return 0;
}
A::A
B::B
B::B copy-constructor
A::attach
B::~B
A::detach 2
B::~B
A::detach 1
A::~A

從log中可以看出,指針成員變量的引用計數(shù)為2,這是正確的,最后正確delete,沒有問題。

在類中只要有指針成員變量,就要注意以上問題,另外,operator=這個賦值操作符也要在適當?shù)臅r候進行重載。有時候,如果想規(guī)避以上問題,可以聲明拷貝構(gòu)造函數(shù)和operator=操作符為private而不去實現(xiàn)它們。

感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!

相關(guān)文章

  • C++中的Primer拷貝控制和資源管理詳解

    C++中的Primer拷貝控制和資源管理詳解

    這篇文章主要介紹了C++中的Primer拷貝控制和資源管理方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • C++11/14 線程中使用Lambda函數(shù)的方法

    C++11/14 線程中使用Lambda函數(shù)的方法

    這篇文章主要介紹了C++11/14 線程中使用Lambda函數(shù)的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-01-01
  • VC通過托盤圖標得到該所屬進程的實現(xiàn)代碼

    VC通過托盤圖標得到該所屬進程的實現(xiàn)代碼

    這篇文章主要介紹了VC通過托盤圖標得到該所屬進程的實現(xiàn)代碼,為了方便大家使用特將多個代碼分享給大家,需要的朋友可以參考下
    2021-10-10
  • 詳解Dev C++使用教程(使用Dev C++編寫C語言程序)

    詳解Dev C++使用教程(使用Dev C++編寫C語言程序)

    這篇文章主要介紹了詳解Dev C++使用教程(使用Dev C++編寫C語言程序),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-03-03
  • C語言strlen和sizeof在數(shù)組中的使用詳解

    C語言strlen和sizeof在數(shù)組中的使用詳解

    對于 strlen 和 sizeof,相信不少程序員會混淆其功能。雖然從表面上看它們都可以求字符串的長度,但二者卻存在著許多不同之處及本質(zhì)區(qū)別
    2021-10-10
  • C++中g(shù)etline()和get()的方法淺析

    C++中g(shù)etline()和get()的方法淺析

    大家都知道作為C++獲取輸入流的方法,幾乎在任何一本資料書上getline()方法和get()方法都作為入門級的方法進行講述,即便如此,筆者在學習C++的過程中仍經(jīng)常忘記這二者的使用要點,可能也有C++的初學者對這兩個方法還心存疑慮,本篇文章就這兩個方法的使用進行簡要闡述。
    2016-10-10
  • 使用C++實現(xiàn)插件模式時的避坑要點(推薦)

    使用C++實現(xiàn)插件模式時的避坑要點(推薦)

    這篇文章主要介紹了使用C++實現(xiàn)插件模式時的避坑要點,本文主要分析實踐中常見的、因為對原理不清楚而搞出來的產(chǎn)品里的坑,本文給大家介紹的非常詳細,需要的朋友可以參考下
    2022-08-08
  • C語言指針之必須要掌握的指針基礎(chǔ)知識

    C語言指針之必須要掌握的指針基礎(chǔ)知識

    這篇文章主要介紹了C語言指針必須要掌握的基礎(chǔ)知識,文中實例講解的很清晰,有不太懂的同學可以研究下,希望能夠給你帶來幫助
    2021-09-09
  • C++ DFS算法實現(xiàn)走迷宮自動尋路

    C++ DFS算法實現(xiàn)走迷宮自動尋路

    這篇文章主要為大家詳細介紹了C++ DFS算法實現(xiàn)走迷宮自動尋路,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-05-05
  • QT實現(xiàn)簡單時鐘效果

    QT實現(xiàn)簡單時鐘效果

    這篇文章主要為大家詳細介紹了QT實現(xiàn)簡單時鐘效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-05-05

最新評論

怀来县| 海兴县| 保德县| 邵阳市| 黄冈市| 宾川县| 繁峙县| 昌都县| 格尔木市| 时尚| 扎囊县| 江口县| 莱西市| 虞城县| 江山市| 丰台区| 安阳市| 江孜县| 山阴县| 临朐县| 新津县| 哈密市| 龙口市| 肃南| 泰兴市| 宁远县| 博乐市| 黄石市| 洛南县| 旌德县| 绵竹市| 腾冲县| 当涂县| 通许县| 武宣县| 彩票| 平泉县| 铁岭县| 平和县| 汨罗市| 荔浦县|