欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解C++中shared_ptr的使用教程

 更新時間:2016年05月31日 18:37:12   作者:wudaijun  
shared_ptr能夠記錄對象被引用的次數(shù),主要被用來管理動態(tài)創(chuàng)建的對象的銷毀,這里我們就來詳解C++中shared_ptr的使用教程,需要的朋友可以參考下

shared_ptr是一種智能指針(smart pointer)。shared_ptr的作用有如同指針,但會記錄有多少個shared_ptrs共同指向一個對象。
這便是所謂的引用計數(shù)(reference counting)。一旦最后一個這樣的指針被銷毀,也就是一旦某個對象的引用計數(shù)變?yōu)?,這個對象會被自動刪除。這在非環(huán)形數(shù)據(jù)結構中防止資源泄露很有幫助。
auto_ptr由于它的破壞性復制語義,無法滿足標準容器對元素的要求,因而不能放在標準容器中;如果我們希望當容器析構時能自動把它容納的指針元素所指的對象刪除時,通常采用一些間接的方式來實現(xiàn),顯得比較繁瑣。boost庫中提供了一種新型的智能指針shared_ptr,它解決了在多個指針間共享對象所有權的問題,同時也滿足容器對元素的要求,因而可以安全地放入容器中。

總結下幾個使用shared_ptr需要注意的問題:

一. 相互引用鏈

class C;
class B : public std::enable_shared_from_this<B>
{
public:
 ~B(){ cout << "~B" << endl; }
 void SetPC(std::shared_ptr<C>& pc){ _pc = pc; } 

private:
 std::shared_ptr<C> _pc;
};

class C : public std::enable_shared_from_this<C>
{
public:
 ~C(){ cout << "~C" << endl; }
 void SetPB(std::shared_ptr<B>& pb){ _pb = pb; }
 
private:
 std::shared_ptr<B> _pb;
};

int main()
{
 std::shared_ptr<C> pc = std::make_shared<C>();
 std::shared_ptr<B> pb = std::make_shared<B>();
 pc->SetPB(pb);
 pb->SetPC(pc);
 return 0;
}

上面的代碼中,B和C均不能正確析構,正確的做法是,在B和C的釋放函數(shù),如Close中,將其包含的shared_ptr置空。這樣才能解開引用鏈。

二. 自引用
還有個比較有意思的例子:

class C : public std::enable_shared_from_this < C >
{
public:

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

 int32_t Decode(const char* data, size_t)
 {
  return 0;
 }
 void SetDecoder(std::function<int32_t(const char*, size_t)> decoder)
 {
  _decoder = decoder;
 }


private:
 std::function<int32_t(const char*, size_t)> _decoder;
};

int main()
{
 {
  std::shared_ptr<C> pc = std::make_shared<C>();
  auto decoder = std::bind(&C::Decode, pc, std::placeholders::_1, std::placeholders::_2);
  pc->SetDecoder(decoder);
 }
 // C不能正確析構 因為存在自引用
 return 0;
}

上面的C類包含了一個function,該function通過std::bind引用了一個std::shared_ptr,所以_decoder其實包含了一個對shared_ptr的引用。導致C自引用了自身,不能正確析構。需要在C的Close之類的執(zhí)行關閉函數(shù)中,將_decoder=nullptr,以解開這種自引用。

三. 類中傳遞
下面的例子中有個更為隱蔽的問題:

class Session : public std::enable_shared_from_this < Session >
{
public:

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

 void Start()
 {
  // 進行一些異步調(diào)用
  // 如 _socket.async_connect(..., boost::bind(&Session::ConnectCompleted, this), boost::asio::placeholders::error, ...)
 }

 void ConnectCompleted(const boost::system::err_code& err)
 {
 if(err)
 return; 

  // ... 進行處理
  // 如 _socket.async_read(..., boost::bind(&Session::ReadCompleted, this), boost::asio::placeholders::error, ...)
 }

 void Session::ReadComplete(const boost::system::error_code& err, size_t bytes_transferred)
 {
  if (err || bytes_transferred == 0)
  {
   DisConnect();
   return;
  }
 // 處理數(shù)據(jù) 繼續(xù)讀
 // ProcessData();
 // _socket.async_read(...)
 }

private:
 std::function<int32_t(const char*, size_t)> _decoder;
};

int main()
{
 {
  std::shared_ptr<Session> pc = std::make_shared<Session>();
  pc->Start();
 }
 return 0;
}

上面Session,在調(diào)用Start時,調(diào)用了異步函數(shù),并回調(diào)自身,如果在回調(diào)函數(shù)的 boost::bind 中 傳入的是shared_from_this(),那么并無問題,shared_ptr將被一直傳遞下去,在網(wǎng)絡處理正常時,Session將正常運行,即使main函數(shù)中已經(jīng)沒有它的引用,但是它靠boost::bind”活了下來”,boost::bind會保存?zhèn)鹘o它的shared_ptr,在調(diào)用函數(shù)時傳入。當網(wǎng)絡遇到錯誤時,函數(shù)直接返回。此時不再有新的bind為其”續(xù)命”。Session將被析構。
而真正的問題在于,如果在整個bind鏈中,直接傳遞了this指針而不是shared_from_this(),那么實際上當函數(shù)執(zhí)行完成后,Session即會析構,包括其內(nèi)部的資源(如 _socket)也會被釋放。那么當boost底層去執(zhí)行網(wǎng)絡IO時,自然會遇到錯誤,并且仍然會”正常”回調(diào)到對應函數(shù),如ReadCompleted,然后在err中告訴你:”由本地系統(tǒng)終止網(wǎng)絡連接”(或:”An attempt to abort the evaluation failed. The process is now in an indeterminate state.” )。讓人誤以為是網(wǎng)絡問題,很難調(diào)試。而事實上此時整個對象都已經(jīng)被釋放掉了。
注:由于C++對象模型實現(xiàn)所致,成員函數(shù)和普通函數(shù)的主要區(qū)別如下:

  • 成員函數(shù)帶隱式this參數(shù)
  • 成員函數(shù)具有訪問作用域,并且函數(shù)內(nèi)會對非靜態(tài)成員變量訪問做一些轉換,如 _member_data 轉換成 this->_member_data;

也就是說,成員函數(shù)并不屬于對象,非靜態(tài)數(shù)據(jù)成員才屬于對象。

因此如下調(diào)用在編譯期是合法的:

((A*)nullptr)->Func();

而如果成員函數(shù)A::Func()沒有訪問A的非靜態(tài)成員變量,這段代碼甚至能正確運行,如:

class Test
{


public:
 void Say()
 {
  std::cout << "Say Test" << std::endl;
 }

 void Set(int data)
 {
  _data = data;
 }

private:
 int _data;
};
int main()
{
 // 運行成功
 ((Test*)nullptr)->Say();
 // 運行會崩掉,嘗試訪問空指針所指內(nèi)存(_data)
 ((Test*)nullptr)->Set(1);
 return 0;
}


正因為這種特性,有時候在成員函數(shù)中糾結半天,也不會注意到這個對象已經(jīng)”不正常了”,被釋放掉了。

四. shared_ptr 使用總結
盡量不要環(huán)引用或自引用,可通過weak_ptr來避免環(huán)引用:owner持有child的shared_ptr child持有owner的weak_ptr
如果存在環(huán)引用或自引用,記得在釋放時解開這個引用鏈
對于通過智能指針管理的類,在類中通過shared_from_this()而不是this來傳遞本身
在類釋放時,盡量手動置空其所有的shared_ptr成員,包括function

相關文章

  • Qt模仿IOS滑動按鈕效果

    Qt模仿IOS滑動按鈕效果

    這篇文章主要為大家詳細介紹了Qt模仿IOS滑動按鈕效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-08-08
  • C++多文件變量解析

    C++多文件變量解析

    大家注意不要在頭文件中定義變量,在頭文件中聲明變量。定義放在對應的源文件中。其他地方只能用extern聲明
    2013-10-10
  • c++常量詳解

    c++常量詳解

    常量是存放固定且不可變值的,一旦確定初始值則在程序其它地方不可改變, 所以const對象必須初始化。常量一般使用const關鍵字來修飾
    2017-06-06
  • c++中關于max_element()函數(shù)解讀

    c++中關于max_element()函數(shù)解讀

    這篇文章主要介紹了c++中關于max_element()函數(shù)解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • 利用Matlab仿真實現(xiàn)圖像煙霧識別(k-means聚類圖像分割+LBP+PCA+SVM)

    利用Matlab仿真實現(xiàn)圖像煙霧識別(k-means聚類圖像分割+LBP+PCA+SVM)

    本文主要介紹了利用k-means聚類實現(xiàn)圖像分割+LBP算法進行特征提取+PCA算法進行特征降維+SVM算法訓練二分類模型從而實現(xiàn)煙霧識別。文中介紹很詳細,感興趣的朋友可以了解一下
    2021-12-12
  • C/C++ 中怎樣使用SetConsoleTextAttribute()函數(shù)來控制輸出字符的顏色

    C/C++ 中怎樣使用SetConsoleTextAttribute()函數(shù)來控制輸出字符的顏色

    這篇文章主要介紹了C/C++ 中如何使用SetConsoleTextAttribute()函數(shù)來控制輸出字符的顏色,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • C++11并發(fā)編程關于原子操作atomic的代碼示例

    C++11并發(fā)編程關于原子操作atomic的代碼示例

    今天小編就為大家分享一篇關于C++11并發(fā)編程關于原子操作atomic的代碼示例,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • C/C++中智能指針的用法詳解

    C/C++中智能指針的用法詳解

    C/C++中,指針是一個非常重要的概念,其強大但也麻煩,麻煩之處就在于一旦你申請了內(nèi)存,那就必須要手動去釋放內(nèi)容,否則就會造成內(nèi)存泄漏。所以智能指針的作用就是防止我們麻痹大意忘記釋放內(nèi)存,幫助我們管理內(nèi)存的,本文就來聊聊智能指針的用法
    2023-01-01
  • C語言基礎全局變量與局部變量教程詳解

    C語言基礎全局變量與局部變量教程詳解

    此處對于全局與局部做一些簡要的介紹,包括全局變量與局部變量,靜態(tài)全局變量與靜態(tài)局部變量,全局函數(shù)與靜態(tài)函數(shù),作者實屬初學,文中若有理解不當之處,還請朋友們不吝指正
    2021-11-11
  • 用C語言實現(xiàn)推箱子游戲實例

    用C語言實現(xiàn)推箱子游戲實例

    大家好,本篇文章主要講的是用C語言實現(xiàn)推箱子游戲實例,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01

最新評論