shared_ptr原始碼分析
shared_ptr與scoped_ptr一樣包裝了new操作符在堆上分配的動態物件,但它實現的是引用技術型的智慧指標,可以自由地被拷貝和賦值,在任意的地方共享它,當沒有程式碼使用(引用計數為0時)它才刪除包裝的動態分配的物件。shared_ptr也可以安全地放到標準容器中,彌補了auto_ptr因為轉移語義而不能把指標作為STL容器的缺陷。
原始碼分析
首先看shared_ptr類:
template<class T> class shared_ptr
{
private:
// Borland 5.5.1 specific workaround
typedef shared_ptr<T> this_type;
public:
typedef typename boost::detail::sp_element< T >::type element_type;
//構造一個空shared_ptr
shared_ptr() BOOST_NOEXCEPT : px( 0 ), pn() // never throws in 1.30+
{
}
//使用指標構造shared_ptr,該Y型別指標必須可以轉換為T型別,Y型別可以和T型別一致
template<class Y> //引數不同意味著支援轉換,Y型別需要能轉換為T型別,比如base-derived
explicit shared_ptr( Y * p ): px( p ), pn() // Y must be complete
{
boost::detail::sp_pointer_construct( this, p, pn ); //為enable_shared_from_this類weak_this_成員初始化,下面會詳述。
/* 下面是它底層底層呼叫的函式,我直接註釋在此處
template< class T, class Y >
inline void sp_pointer_construct( boost::shared_ptr< T > * ppx, Y * p, boost::detail::shared_count & pn )
{
boost::detail::shared_count( p ).swap( pn );
boost::detail::sp_enable_shared_from_this( ppx, p, p );
}
*/
}
//
// Requirements: D's copy constructor must not throw
//
// shared_ptr will release p by calling d(p)
//
//指標、刪除器
template<class Y, class D> shared_ptr( Y * p, D d ): px( p ), pn( p, d )
{
boost::detail::sp_deleter_construct( this, p );
/*同上,註釋
template< class T, class Y > inline void sp_deleter_construct( boost::shared_ptr< T > * ppx, Y * p )
{
boost::detail::sp_enable_shared_from_this( ppx, p, p );
}
*/
}
// As above, but with allocator. A's copy constructor shall not throw.
//指標、刪除器、分配器
template<class Y, class D, class A> shared_ptr( Y * p, D d, A a ): px( p ), pn( p, d, a )
{
boost::detail::sp_deleter_construct( this, p );
}
// generated copy constructor, destructor are fine...
#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
// ... except in C++0x, move disables the implicit copy //除了在C++ 0x中,移動構造會遮蔽隱式拷貝構造
shared_ptr( shared_ptr const & r ) BOOST_NOEXCEPT : px( r.px ), pn( r.pn )
{
}
#endif
template<class Y>
explicit shared_ptr( weak_ptr<Y> const & r ): pn( r.pn ) // may throw
{
boost::detail::sp_assert_convertible< Y, T >(); //檢測Y和T型別是否可以轉換
// it is now safe to copy r.px, as pn(r.pn) did not throw
px = r.px;
}
template<class Y>
shared_ptr( weak_ptr<Y> const & r, boost::detail::sp_nothrow_tag ) //不丟擲異常的版本
BOOST_NOEXCEPT : px( 0 ), pn( r.pn, boost::detail::sp_nothrow_tag() )
{
if( !pn.empty() )
{
px = r.px;
}
}
template<class Y>
shared_ptr( shared_ptr<Y> const & r ) //使用shared_ptr構造
BOOST_NOEXCEPT : px( r.px ), pn( r.pn )
{
boost::detail::sp_assert_convertible< Y, T >();
}
//意思就是用p構造本shared_ptr,但是本shared_ptr和r共享引用計數,即便本shared_ptr呼叫reset,只要r不死,那本shared_ptr也不死。共享引用計數兩方都可以加減引用計數。
// aliasing
template< class Y >
shared_ptr( shared_ptr<Y> const & r, element_type * p ) BOOST_NOEXCEPT : px( p ), pn( r.pn )
{
}
#ifndef BOOST_NO_AUTO_PTR
//FIXME
//注意這裡用的auto_ptr的引用,並且沒有呼叫auto_ptr的release函式,shared_count(r)中會呼叫
//shared_ptr從一個auto_ptr獲得指標的管理權,引用計數置位1,同時auto_ptr將自動失去管理權
template<class Y>
explicit shared_ptr( std::auto_ptr<Y> & r ): px(r.get()), pn()
{
boost::detail::sp_assert_convertible< Y, T >();
Y * tmp = r.get();
pn = boost::detail::shared_count( r );
boost::detail::sp_deleter_construct( this, tmp );
}
#if !defined( BOOST_NO_CXX11_SMART_PTR ) && !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
template< class Y, class D >
shared_ptr( std::unique_ptr< Y, D > && r ): px( r.get() ), pn()
{
boost::detail::sp_assert_convertible< Y, T >();
typename std::unique_ptr< Y, D >::pointer tmp = r.get();
pn = boost::detail::shared_count( r );
boost::detail::sp_deleter_construct( this, tmp );
}
#endif
// assignment
shared_ptr & operator=( shared_ptr const & r ) BOOST_NOEXCEPT
{
this_type(r).swap(*this);
return *this;
}
#ifndef BOOST_NO_AUTO_PTR
template<class Y>
shared_ptr & operator=( std::auto_ptr<Y> & r )
{
this_type( r ).swap( *this );
return *this;
}
#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
template<class Y>
shared_ptr & operator=( std::auto_ptr<Y> && r )
{
this_type( static_cast< std::auto_ptr<Y> && >( r ) ).swap( *this );
return *this;
}
#endif // BOOST_NO_AUTO_PTR
#if !defined( BOOST_NO_CXX11_SMART_PTR ) && !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
//支援C++11的unique_ptr
template<class Y, class D>
shared_ptr & operator=( std::unique_ptr<Y, D> && r )
{
this_type( static_cast< std::unique_ptr<Y, D> && >( r ) ).swap(*this);
return *this;
}
#endif
// Move support
shared_ptr( shared_ptr && r ) BOOST_NOEXCEPT : px( r.px ), pn()
{
pn.swap( r.pn );
r.px = 0;
}
template<class Y>
shared_ptr( shared_ptr<Y> && r ) //C++11的移動構造
BOOST_NOEXCEPT : px( r.px ), pn()
{
boost::detail::sp_assert_convertible< Y, T >();
pn.swap( r.pn );
r.px = 0;
}
shared_ptr & operator=( shared_ptr && r ) BOOST_NOEXCEPT
{
this_type( static_cast< shared_ptr && >( r ) ).swap( *this );
return *this;
}
//僅重置
void reset() BOOST_NOEXCEPT // never throws in 1.30+
{
this_type().swap(*this); //666,直接構造一個null物件和this交換
}
//重置為p
template<class Y> void reset( Y * p ) // Y must be complete
{
BOOST_ASSERT( p == 0 || p != px ); // catch self-reset errors
this_type( p ).swap( *this );
}
//這裡省略reset的另外兩個版本:(1)重置為p指標,帶有一個刪除器。(2)重置為p指標,帶有刪除器和記憶體分配器。
//共享引用計數的模式
template<class Y> void reset( shared_ptr<Y> const & r, element_type * p )
{
this_type( r, p ).swap( *this );
}
// never throws (but has a BOOST_ASSERT in it, so not marked with BOOST_NOEXCEPT)
typename boost::detail::sp_dereference< T >::type operator* () const
{
BOOST_ASSERT( px != 0 );
return *px;
}
// never throws (but has a BOOST_ASSERT in it, so not marked with BOOST_NOEXCEPT)
typename boost::detail::sp_member_access< T >::type operator-> () const
{
BOOST_ASSERT( px != 0 );
return px;
}
// never throws (but has a BOOST_ASSERT in it, so not marked with BOOST_NOEXCEPT)
typename boost::detail::sp_array_access< T >::type operator[] ( std::ptrdiff_t i ) const
{
BOOST_ASSERT( px != 0 );
BOOST_ASSERT( i >= 0 && ( i < boost::detail::sp_extent< T >::value || boost::detail::sp_extent< T >::value == 0 ) );
return px[ i ];
}
element_type * get() const BOOST_NOEXCEPT
{
return px;
}
// implicit conversion to "bool"
#include <boost/smart_ptr/detail/operator_bool.hpp> //過載operator bool
//返回引用計數是否為1
bool unique() const BOOST_NOEXCEPT
{
return pn.unique();
}
//返回引用計數
long use_count() const BOOST_NOEXCEPT
{
return pn.use_count();
}
//異常安全的swap,可配合no-member swap函式
void swap( shared_ptr & other ) BOOST_NOEXCEPT
{
std::swap(px, other.px);
pn.swap(other.pn);
}
//可以理解為是不是要早死嗎?
template<class Y> bool owner_before( shared_ptr<Y> const & rhs ) const BOOST_NOEXCEPT
{
return pn < rhs.pn;
}
template<class Y> bool owner_before( weak_ptr<Y> const & rhs ) const BOOST_NOEXCEPT
{
return pn < rhs.pn;
}
//用於內部獲取刪除器,如果沒有返回空,即非刪除器構造
void * _internal_get_deleter( boost::detail::sp_typeinfo const & ti ) const BOOST_NOEXCEPT
{
return pn.get_deleter( ti );
}
void * _internal_get_untyped_deleter() const BOOST_NOEXCEPT
{
return pn.get_untyped_deleter();
}
//成員函式比較是否相等,shared_ptr也提供非成員函式比較的方式
bool _internal_equiv( shared_ptr const & r ) const BOOST_NOEXCEPT
{
return px == r.px && pn == r.pn;
}
// Tasteless as this may seem, making all members public allows member templates
// to work in the absence of member template friends. (Matthew Langston)
private:
template<class Y> friend class shared_ptr;
template<class Y> friend class weak_ptr;
element_type * px; // contained pointer
boost::detail::shared_count pn; // reference counter
}; // shared_ptr
上面就是shared_ptr的大致原始碼,我把一些過多的預處理巨集,都去掉了。還有過多的C++11的東西,不過仍然保留了部分如移動構造,以及unique_ptr。
shared_ptr可以由一個普通指標構造,它也可以在類內部使用shared_from_this構造(與建構函式那一句有關,稍後分析),甚至auto_ptr或是unique_ptr也都可以。
下面來看shared_ptr的建構函式中奇怪的那一句:
template<class Y>
explicit shared_ptr( Y * p ): px( p ), pn() // px是被管理的物件指標;pn是引用計數器,shared_ptr內部管理
{
boost::detail::sp_pointer_construct( this, p, pn ); // 開始構造
}
template< class T, class Y > inline void sp_pointer_construct( boost::shared_ptr< T > * ppx, Y * p, boost::detail::shared_count & pn )
{ //至於為什麼用swap來構造pn,我認為這是為了異常安全,因為pn建構函式中用到了new
boost::detail::shared_count( p ).swap( pn ); // 建立引用計數器,swap等價於賦值給pn
boost::detail::sp_enable_shared_from_this( ppx, p, p );
}
// sp_enable_shared_from_this 模板過載了多個,針對被管理的是enable_shared_from_this的派生類的物件時自動選擇執行這個函式
template< class X, class Y, class T > inline void sp_enable_shared_from_this( boost::shared_ptr<X> const * ppx, Y const * py, boost::enable_shared_from_this< T > const * pe ) //注第三個引數型別是enable_shared_from_this,使用基類指標指向派生類
{
if( pe != 0 )
{
pe->_internal_accept_owner( ppx, const_cast< Y* >( py ) );
}
}
template<class T> class enable_shared_from_this
{
public:
// 獲取指向自身的智慧指標,weak_ptr作為觀察者能夠判斷指標是否已經釋放
shared_ptr<T> shared_from_this()
{
shared_ptr<T> p( weak_this_ );
BOOST_ASSERT( p.get() == this ); // 如果指標已經釋放,那麼這裡就會報錯了
return p;
}
shared_ptr<T const> shared_from_this() const
{
shared_ptr<T const> p( weak_this_ );
BOOST_ASSERT( p.get() == this );
return p;
}
public:
// 派生物件內部儲存一份私有的weak_ptr,用來獲取指向自身(this)的智慧指標
// Note: invoked automatically by shared_ptr; do not call
template<class X, class Y> void _internal_accept_owner( shared_ptr<X> const * ppx, Y * py ) const
{
if( weak_this_.expired() )
{
weak_this_ = shared_ptr<T>( *ppx, py ); //這裡就構造了一個weak_ptr,且其目前監視的物件引用計數為1,
//呼叫shread_ptr的shared_ptr( shared_ptr<Y> const & r, element_type * p ),使用p構造一個shared_ptr和r共享引用計數,而r正是我們最初要構造的shared_ptr的this指標,p即我們最初傳給shared_ptr的引數
//所以這裡相當於賦值該weak_ptr,以後該weak_ptr就監視本shared_ptr了
//為什麼說賦值,因為weak_count已經預設初始化過了,只不過weak_count之前為0,詳見enable_shared_from_this類建構函式
}
}
private:
mutable weak_ptr<T> weak_this_;
};
上面這一大堆起了什麼作用呢?答案就是初始化enable_shared_from_this相關的引用計數。有了這個我們就可以這樣用了:
class Y: public boost::enable_shared_from_this<Y>
{
public:
boost::shared_ptr<Y> f()
{
return shared_from_this();
}
};
// 正確的使用方法
boost::shared_ptr<Y> p(new Y);
boost::shared_ptr<Y> q = p->f();
// 錯誤的使用方法,因為Y的成員weak_ptr 根本就沒有得到初始化,必須先使用shared_ptr管理class才可以
Y yy;
boost::shared_ptr<Y> q = yy.f();
好了,建構函式就分析到這裡,至於sp_deleter_construct()函式,和這個流程一致,只不過加了個刪除器而已。
操作函式
shared_ptr與scoped_ptr同樣是用於管理new動態分配物件的智慧指標,因此功能上有很多相似之處:它們都過載了*和->操作符以模仿原始指標的行為,提供隱式bool型別轉換以判斷指標的有效性,get可以得到原始指標(return px),並且沒有提供指標算數操作。
例如:
shared_ptr<int> spi(new int);
assert(spi);
*spi = 253;
shared_ptr<string> sps(new string("smart"));
assert(sps->size() == 5);
shared_ptr有多種形式建構函式,應用於各種可能的情形:
- 無參的shared_ptr()建立一個持有空指標的shared_ptr;
- shared_ptr(Y* p)獲得指向型別T的指標p的管理權,同時引用計數置為1.這個建構函式要求Y型別必須能夠轉換為T型別;
- shared_ptr(shared_ptr const & r)從另外一個shared_ptr獲得指標的管理權,同時引用計數加1,結果是兩個shared_ptr共享一個指標的管理權;
- shared_ptr(std::auto_ptr< Y> &r)從另外一個auto_ptr獲得指標的管理權,引用計數置為1,同時auto_ptr自動失去管理權;
- operator=賦值操作符可以從另外一個shared_ptr或auto_ptr獲得指標的管理權,其行為同建構函式。
- shared_ptr(Y *p, D d)行為類似shared_ptr(Y *p),但是用引數d指定了析構時定值刪除器,而不是簡單的delete。
shared_ptr的reset()函式與scoped_ptr也不盡相同。它的作用是將引用計數減1,停止對指標的共享,除非引用計數為0,否則不會發生刪除操作。帶引數的reset()則是類似相同形式的建構函式,原指標引用計數減1的同時改為管理另一個指標。
shared_ptr有兩個專門的函式檢查引用計數。unique()檢查shared_ptr是指標唯一所有者返回true,use_count()返回當前引用計數。use_count()應該僅用於測試或除錯,它不提供高效的操作,而且有可能是不可用的(極少數情形)。
shared_ptr還支援比較運算,可以測試兩個shared_ptr的相等或不相等,比較基於內部儲存的指標,相當於a.get()==b.get()。shared_ptr還可以使用operator<比較大小。同樣基於內部儲存的指標,但不提供除operator<之外的比較操作符,這使得shared_ptr可以被用於標準關聯容器(set和map)。
**shared_ptr的型別轉換不能使用static_cast之流,只能使用shared_ptr自己提供的轉型函式:static_pointer_cast()、const_pointer_cast()、dynamic_pointer_cast()和reinterpret_cast()函式,它們轉型後棵正確返回shared_ptr型別。
此外,shared_ptr還支援流輸出操作符operator<<,輸出內部指標值,方便除錯。
相關程式碼如下:
template<class T, class U> inline bool operator<(shared_ptr<T> const & a, shared_ptr<U> const & b) BOOST_NOEXCEPT
{
return a.owner_before( b );
}
template<class T> inline void swap(shared_ptr<T> & a, shared_ptr<T> & b) BOOST_NOEXCEPT
{
a.swap(b);
}
template<class T, class U> shared_ptr<T> static_pointer_cast( shared_ptr<U> const & r ) BOOST_NOEXCEPT
{
(void) static_cast< T* >( static_cast< U* >( 0 ) );
typedef typename shared_ptr<T>::element_type E;
E * p = static_cast< E* >( r.get() );
return shared_ptr<T>( r, p );
}
template<class T, class U> shared_ptr<T> const_pointer_cast( shared_ptr<U> const & r ) BOOST_NOEXCEPT
{
(void) const_cast< T* >( static_cast< U* >( 0 ) );
typedef typename shared_ptr<T>::element_type E;
E * p = const_cast< E* >( r.get() );
return shared_ptr<T>( r, p );
}
template<class T, class U> shared_ptr<T> dynamic_pointer_cast( shared_ptr<U> const & r ) BOOST_NOEXCEPT
{
(void) dynamic_cast< T* >( static_cast< U* >( 0 ) );
typedef typename shared_ptr<T>::element_type E;
E * p = dynamic_cast< E* >( r.get() );
return p? shared_ptr<T>( r, p ): shared_ptr<T>();
}
template<class T, class U> shared_ptr<T> reinterpret_pointer_cast( shared_ptr<U> const & r ) BOOST_NOEXCEPT
{
(void) reinterpret_cast< T* >( static_cast< U* >( 0 ) );
typedef typename shared_ptr<T>::element_type E;
E * p = reinterpret_cast< E* >( r.get() );
return shared_ptr<T>( r, p );
}
用法
這裡只給出一些特殊用法:
class socket_t {};
socket_t* open_socket()
{
cout<<"open socket"<<endl;
return new socket_t;
}
void close_socket(socket_t *s)
{
cout<<"close_socket"<<endl;
}
void anyfunc(void *)
{
cout<<"hehe"<<endl;
}
int main()
{
socket_t *s = open_socket();
shared_ptr<socket_t> p(s, close_socket);
// shared_ptr<FILE> fp(fopen("./1.txt","r"), fclose);
shared_ptr<void> v((void*)0, anyfunc);
return 0;
}
上面出現了兩種特殊用法:
- 定值刪除器,如上close_socket函式
- 使用shared_ptr,在作用域結束時可呼叫任何函式 :)
本次簡單剖析了shared_ptr的類原始碼,至於shared_count等限於篇幅放在後續部落格。
參考:
- 《Boost程式庫完全開發指南》,作者:羅劍鋒
- Boost shared_from_this用法
- http://bbs.csdn.net/topics/390872556
相關文章
- shared_ptr原始碼分析後續原始碼
- Retrofit原始碼分析三 原始碼分析原始碼
- 集合原始碼分析[2]-AbstractList 原始碼分析原始碼
- 集合原始碼分析[1]-Collection 原始碼分析原始碼
- 集合原始碼分析[3]-ArrayList 原始碼分析原始碼
- Guava 原始碼分析之 EventBus 原始碼分析Guava原始碼
- Android 原始碼分析之 AsyncTask 原始碼分析Android原始碼
- 【JDK原始碼分析系列】ArrayBlockingQueue原始碼分析JDK原始碼BloC
- 以太坊原始碼分析(36)ethdb原始碼分析原始碼
- 以太坊原始碼分析(38)event原始碼分析原始碼
- 以太坊原始碼分析(41)hashimoto原始碼分析原始碼
- 以太坊原始碼分析(43)node原始碼分析原始碼
- 以太坊原始碼分析(52)trie原始碼分析原始碼
- 深度 Mybatis 3 原始碼分析(一)SqlSessionFactoryBuilder原始碼分析MyBatis原始碼SQLSessionUI
- 以太坊原始碼分析(51)rpc原始碼分析原始碼RPC
- 【Android原始碼】Fragment 原始碼分析Android原始碼Fragment
- 【Android原始碼】Intent 原始碼分析Android原始碼Intent
- k8s client-go原始碼分析 informer原始碼分析(6)-Indexer原始碼分析K8SclientGo原始碼ORMIndex
- k8s client-go原始碼分析 informer原始碼分析(4)-DeltaFIFO原始碼分析K8SclientGo原始碼ORM
- 以太坊原始碼分析(20)core-bloombits原始碼分析原始碼OOM
- 以太坊原始碼分析(24)core-state原始碼分析原始碼
- 以太坊原始碼分析(29)core-vm原始碼分析原始碼
- 【MyBatis原始碼分析】select原始碼分析及小結MyBatis原始碼
- redis原始碼分析(二)、redis原始碼分析之sds字串Redis原始碼字串
- ArrayList 原始碼分析原始碼
- kubeproxy原始碼分析原始碼
- [原始碼分析]ArrayList原始碼
- redux原始碼分析Redux原始碼
- preact原始碼分析React原始碼
- Snackbar原始碼分析原始碼
- React原始碼分析React原始碼
- CAS原始碼分析原始碼
- Redux 原始碼分析Redux原始碼
- SDWebImage 原始碼分析Web原始碼
- Aspects原始碼分析原始碼
- httprouter 原始碼分析HTTP原始碼
- PowerManagerService原始碼分析原始碼
- HashSet原始碼分析原始碼