Boost 關於 shared_ptr 的學習心得

今天學習了boost 的智能指針中的shared_ptr,感覺收穫頗多,現在就寫下來,一則作爲學習筆記,二則與大家分享我的學習心得

shared_ptr智能指針我想大家如果看過《C++Primer》第四版(16.5 A generic handle class 一個泛型句柄)的話,應該瞭解作者構造了一個通過引用計數的方法來管理指針的,

沒錯shared_ptr 同樣是這樣實現的,首先先看一下書中的實現:


看完上面的代碼我想你應該瞭解智能指針是如何工作的了吧,看過書本的可以當做一次複習;

對於shard_ptr的結構如何使用我想我不用做過多介紹,看一下頭文件再結合文檔和網上的一些資料應該很快就明白

下面我展示一下shared_ptr的一個用法:

#include <iostream>
#include "boost/shared_ptr.hpp"
using namespace std;
using namespace boost;
class A
{
	public:
	A(){}
    virtual  void mem_func() = 0;
   protected:
   virtual ~A()
   {
      cout<<"A's dector\n";
   }

	private:

};

class B:public A
{
	public:
	B(){}
	virtual void mem_func()
	{
	   cout<<"I'm mem_fun\n";
	}

};
shared_ptr<A> create()
{
   return shared_ptr<A>(new B);
}
int main()
{
       shared_ptr<A> sp = create();
       sp->mem_func();
      return 0;
}

請注意,上面的代碼,A的析構函數被定義爲protect,而它在程序結束時候被調用了,這個就是我要將的地方了,我們通過源碼來分析一下

首先shared_ptr在內部有兩個私有成員:

    T * px;                     // contained pointer
    boost::detail::shared_count pn;    // reference counter

其中 px是原生的指針,也就是 new B 得到的指針,但是他是A * 類型的,shared_ptr通過它來快速訪問內存,shared_ptr重載* , ->來讓用戶像使用原生指針一樣來使用,

但是在刪除這塊內存時,shared_ptr不是直接這樣 delete px的,因爲~A 是protect,這樣釋放內存會報錯,你可是測試一下的代碼就知道了

A * pa = new B;

delete pa;

編譯器會報錯如:

而你這樣定義 A  a同樣也編譯不過,但是前面的代碼明明調用了基類A 的析構函數 打印出了 A‘ dector,不急,往下看pn 這個變量

 pn 這個東東就大有來頭了,要完全弄懂,我想我還沒那能力,裏面涉及到了一些平臺相關的知識,我只講爲何會跳用了~A;

其實跟蹤pn 可以發現它是:shared_count 類型,它保存一個計數值,也就是如C++Primer中的那個 user ,但是它還保存有一個指針

就是在構造shared_ptr的時候傳就去的那個new B,注意是B *類型的指針,px保存的是A* 基類的指針,當pn 的計數值爲0的是後就會

delete這個指針,可以看一下shared_ptr的一個構造函數你就會明白它是如何工作的了:

  template<class T>

class shared_ptr{

.............

public:

..........

    template<class Y>
    explicit shared_ptr( Y * p ): px( p ), pn( p ) // Y must be complete
    {
        boost::detail::sp_enable_shared_from_this( this, p, p );
    }

...........

private:

    T * px;                     // contained pointer
    boost::detail::shared_count pn;    // reference counter

};

請注意 在 shared_ptr<A>(new B)中,模板類型 T *是 一個 A * , shared_ptr調用的是一個模板構造函數shared_ptr( Y * p )中的Y* 是 B*,而px(p)

等價於 A* px = B* p ,而對於pn,下面是我從源代碼裏面複製出來的一個pn的構造構造函數頭

    template<class Y> explicit shared_count( Y * p ): pi_( 0 )
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
        , id_(shared_count_id)

可以看到pn也是一個模板,傳遞過來的 Y * p 就是 就是 shared_ptr<A>(new B)中的new B 了,當計數器爲0是就會析構掉這個B* 指針,所以可以知道

其實px與pn內保持的指針類型是不一樣的,px 的是A* 而 pn的是 A 的子類 B 的指針,這樣       B* pb = new B;    delete pb;是妹問題的。

對於pn 裏面複雜的實現我暫時還沒能完全理解,有時間再慢慢研究,感興趣的可以自己去看源代碼


全文完!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章