shared_ptr原始碼分析後續
上次剖析了shared_ptr類的原始碼,本來肯定也是要說shared_count的,不過由於篇幅,shared_count在這篇部落格分析。
shared_ptr類自身有兩個成員,一個就是T型別指標,另一個就是shared_count物件了。shared_ptr把所有的計數任務都交給了該成員,最終指標的銷燬也是由該物件去執行的(底層實際還有sp_counted_base)。這是一種解耦的思想。
原始碼分析:
class weak_count;
class shared_count
{
private:
sp_counted_base * pi_;
friend class weak_count;
public:
shared_count(): pi_(0) // nothrow
{
}
template<class Y> explicit shared_count( Y * p ): pi_( 0 )
{
pi_ = new sp_counted_impl_p<Y>( p ); //new一個impl派生類
if( pi_ == 0 ) //如果失敗,就摧毀,這是在定義了BOOST_NO_EXCEPTION情況下,new失敗返回值為0。巨集定義被我略去。
{
boost::checked_delete( p );
boost::throw_exception( std::bad_alloc() );
}
}
//刪除器版本
template<class P, class D> shared_count( P p, D d ): pi_(0)
{
pi_ = new sp_counted_impl_pd<P, D>(p, d);
if(pi_ == 0)
{
d(p); // delete p
boost::throw_exception(std::bad_alloc());
}
}
//分配器版本
template<class P, class D, class A> shared_count( P p, D d, A a ): pi_( 0 )
{
typedef sp_counted_impl_pda<P, D, A> impl_type;
typedef typename A::template rebind< impl_type >::other A2;
A2 a2( a );
pi_ = a2.allocate( 1, static_cast< impl_type* >( 0 ) );
if( pi_ != 0 )
{
new( static_cast< void* >( pi_ ) ) impl_type( p, d, a );
}
else
{
d( p ); //失敗要執行d(),銷燬操作。
boost::throw_exception( std::bad_alloc() );
}
}
#ifndef BOOST_NO_AUTO_PTR
// auto_ptr<Y> is special cased to provide the strong guarantee
//auto_ptr版本,不過C++11已經棄用auto_ptr了
template<class Y>
explicit shared_count( std::auto_ptr<Y> & r ): pi_( new sp_counted_impl_p<Y>( r.get() ) )
{
r.release(); //在這裡release的,呵呵
}
#endif
#if !defined( BOOST_NO_CXX11_SMART_PTR )
//C++11的unique_ptr版本。
template<class Y, class D>
explicit shared_count( std::unique_ptr<Y, D> & r ): pi_( 0 )
{
typedef typename sp_convert_reference<D>::type D2;
D2 d2( r.get_deleter() );
pi_ = new sp_counted_impl_pd< typename std::unique_ptr<Y, D>::pointer, D2 >( r.get(), d2 );
r.release();
}
#endif
~shared_count() // nothrow
{
if( pi_ != 0 ) pi_->release();
}
shared_count(shared_count const & r): pi_(r.pi_) // nothrow
{
if( pi_ != 0 ) pi_->add_ref_copy();
}
explicit shared_count(weak_count const & r); // throws bad_weak_ptr when r.use_count() == 0
shared_count( weak_count const & r, sp_nothrow_tag ); // constructs an empty *this when r.use_count() == 0
//賦值操作
shared_count & operator= (shared_count const & r) // nothrow
{
sp_counted_base * tmp = r.pi_;
if( tmp != pi_ )
{
if( tmp != 0 ) tmp->add_ref_copy();
if( pi_ != 0 ) pi_->release();
pi_ = tmp;
}
return *this;
}
void swap(shared_count & r) // nothrow
{
sp_counted_base * tmp = r.pi_;
r.pi_ = pi_;
pi_ = tmp;
}
long use_count() const // nothrow
{
return pi_ != 0? pi_->use_count(): 0;
}
bool unique() const // nothrow
{
return use_count() == 1;
}
bool empty() const // nothrow
{
return pi_ == 0;
}
friend inline bool operator==(shared_count const & a, shared_count const & b)
{
return a.pi_ == b.pi_;
}
friend inline bool operator<(shared_count const & a, shared_count const & b)
{
return std::less<sp_counted_base *>()( a.pi_, b.pi_ );
}
void * get_deleter( sp_typeinfo const & ti ) const
{
return pi_? pi_->get_deleter( ti ): 0;
}
void * get_untyped_deleter() const
{
return pi_? pi_->get_untyped_deleter(): 0;
}
};
class weak_count
{
private:
sp_counted_base * pi_;
friend class shared_count;
public:
weak_count(): pi_(0) // nothrow
{
}
weak_count(shared_count const & r): pi_(r.pi_) // nothrow
{
if(pi_ != 0) pi_->weak_add_ref();
}
weak_count(weak_count const & r): pi_(r.pi_) // nothrow
{
if(pi_ != 0) pi_->weak_add_ref();
}
// Move support
#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
weak_count(weak_count && r): pi_(r.pi_) // nothrow
{
r.pi_ = 0;
}
#endif
~weak_count() // nothrow
{
if(pi_ != 0) pi_->weak_release(); //weak_count析構一次,就減少一次sp_count_base的計數!!!!!!
}
weak_count & operator= (shared_count const & r) // nothrow
{
sp_counted_base * tmp = r.pi_;
if( tmp != pi_ )
{
if(tmp != 0) tmp->weak_add_ref();
if(pi_ != 0) pi_->weak_release();
pi_ = tmp;
}
return *this;
}
weak_count & operator= (weak_count const & r) // nothrow
{
sp_counted_base * tmp = r.pi_;
if( tmp != pi_ )
{
if(tmp != 0) tmp->weak_add_ref();
if(pi_ != 0) pi_->weak_release();
pi_ = tmp;
}
return *this;
}
void swap(weak_count & r) // nothrow
{
sp_counted_base * tmp = r.pi_;
r.pi_ = pi_;
pi_ = tmp;
}
long use_count() const // nothrow
{
return pi_ != 0? pi_->use_count(): 0;
}
bool empty() const // nothrow
{
return pi_ == 0;
}
friend inline bool operator==(weak_count const & a, weak_count const & b)
{
return a.pi_ == b.pi_;
}
friend inline bool operator<(weak_count const & a, weak_count const & b)
{
return std::less<sp_counted_base *>()(a.pi_, b.pi_);
}
};
//在這裡初始化shared_count中的那兩個函式,即利用wakt_count的sp_count_base初始化share_count的sp_count_base,它們是共享的
//這是在呼叫weak_ptr的lock函式用weak_ptr構造shared_ptr,然後呼叫本函式的
inline shared_count::shared_count( weak_count const & r ): pi_( r.pi_ )
{
if( pi_ == 0 || !pi_->add_ref_lock() )
{
boost::throw_exception( boost::bad_weak_ptr() );
}
}
inline shared_count::shared_count( weak_count const & r, sp_nothrow_tag ): pi_( r.pi_ )
{
if( pi_ != 0 && !pi_->add_ref_lock() )
{
pi_ = 0;
}
}
由於shared_count和weak_count在一個標頭檔案中,就一併拿過來了。
shared_count和weak_count如果擁有同一份指標物件,僅有shared_count會增加shared_ptr的引用計數,而weak_count不會。weak_count只是一個觀察者。
sp_counted_base
shared_count和weak_count共同維護一個sp_counted_base類物件,當shared_count引用計數為0時,shared_ptr會銷燬,但是sp_counted_base不一定銷燬,因為它還取決於weak_count,這是weak_ptr自身的引用計數,和shared_ptr無關,當這個引用計數為0時,sp_counted_base自然會呼叫delete this了。
sp_counted_base類負責了shared_ptr的所有引用計數的計數工作。它是一個基類,它的派生類可以定製不同的刪除操作,這對刪除器的實現大有幫助。實際上主流平臺目前採用原子操作,下面是gcc的版本。
sp_counted_base類程式碼如下:
class sp_counted_base
{
private:
sp_counted_base( sp_counted_base const & );
sp_counted_base & operator= ( sp_counted_base const & );
int use_count_; // #shared
int weak_count_; // #weak + (#shared != 0)
public:
sp_counted_base(): use_count_( 1 ), weak_count_( 1 )
{
}
virtual ~sp_counted_base() // nothrow
{
}
// dispose() is called when use_count_ drops to zero, to release
// the resources managed by *this.
virtual void dispose() = 0; // nothrow
// destroy() is called when weak_count_ drops to zero.
virtual void destroy() // nothrow
{
delete this;
}
virtual void * get_deleter( sp_typeinfo const & ti ) = 0;
virtual void * get_untyped_deleter() = 0;
void add_ref_copy()
{
atomic_increment( &use_count_ );
}
bool add_ref_lock() // true on success
{
return atomic_conditional_increment( &use_count_ ) != 0;
}
void release() // nothrow
{
if( atomic_exchange_and_add( &use_count_, -1 ) == 1 )
{
dispose();
weak_release(); //也要執行weak_release,不過由於weak_count不一定為0,所以本release函式沒有呼叫destroy
}
}
//臥槽weak_ptr的weak_count雖然不影響shared_ptr的計數,但是weak_ptr自身也是引用計數只能指標,自身拷貝會增加weak_count
void weak_add_ref() // nothrow
{
atomic_increment( &weak_count_ );
}
void weak_release() // nothrow //本函式是release函式中呼叫的,但只有use_count和weak_count都為0,才銷燬sp_counted_bases
{
if( atomic_exchange_and_add( &weak_count_, -1 ) == 1 )
{
destroy();
}
}
long use_count() const // nothrow
{
return static_cast<int const volatile &>( use_count_ );
}
};
那我們來看一下它的派生類,看一下派生類如何實現dispose操作的:
template<class X> class sp_counted_impl_p: public sp_counted_base
{
private:
X * px_;
sp_counted_impl_p( sp_counted_impl_p const & );
sp_counted_impl_p & operator= ( sp_counted_impl_p const & );
typedef sp_counted_impl_p<X> this_type;
public:
explicit sp_counted_impl_p( X * px ): px_( px )
{
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
boost::sp_scalar_constructor_hook( px, sizeof(X), this );
#endif
}
virtual void dispose() // nothrow
{
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
boost::sp_scalar_destructor_hook( px_, sizeof(X), this );
#endif
boost::checked_delete( px_ ); //check_delete底層檢查指標是否為complete型別,是就直接delete px,之前說過,不再贅述
}
virtual void * get_deleter( detail::sp_typeinfo const & ) //沒有刪除器,但是要返回空
{
return 0;
}
virtual void * get_untyped_deleter()
{
return 0;
}
#if defined(BOOST_SP_USE_STD_ALLOCATOR)
void * operator new( std::size_t )
{
return std::allocator<this_type>().allocate( 1, static_cast<this_type *>(0) );
}
void operator delete( void * p )
{
std::allocator<this_type>().deallocate( static_cast<this_type *>(p), 1 );
}
#endif
#if defined(BOOST_SP_USE_QUICK_ALLOCATOR)
void * operator new( std::size_t )
{
return quick_allocator<this_type>::alloc();
}
void operator delete( void * p )
{
quick_allocator<this_type>::dealloc( p );
}
#endif
};
//刪除器版本
template<class P, class D> class sp_counted_impl_pd: public sp_counted_base
{
private:
P ptr; // copy constructor must not throw
D del; // copy constructor must not throw
...
public:
// pre: d(p) must not throw
sp_counted_impl_pd( P p, D & d ): ptr( p ), del( d )
{
}
sp_counted_impl_pd( P p ): ptr( p ), del()
{
}
virtual void dispose() // nothrow //這就是使用自定義的刪除器,這是和普通指標不同的地方
{
del( ptr );
}
virtual void * get_deleter( detail::sp_typeinfo const & ti ) //返回刪除器指標
{
return ti == BOOST_SP_TYPEID(D)? &reinterpret_cast<char&>( del ): 0;
}
virtual void * get_untyped_deleter()
{
return &reinterpret_cast<char&>( del );
}
#if defined(BOOST_SP_USE_STD_ALLOCATOR)
void * operator new( std::size_t )
{
return std::allocator<this_type>().allocate( 1, static_cast<this_type *>(0) );
}
void operator delete( void * p )
{
std::allocator<this_type>().deallocate( static_cast<this_type *>(p), 1 );
}
#endif
};
還有個定值Allocaor的派生類,就不再分析了。上面兩個派生類最重要的的區別就是刪除方法不同,一個直接delete,而另一個使用刪除器,可能是回撥函式。這就是另一種層面的多型。
總結:shared_ptr把所有的計數工作都交給了shared_count類,該類持有一個sp_counted_base型別的指標,sp_counted_base類有兩個基類,使用不同的刪除方法。shared_count類在建構函式中會new不同的基類初始化sp_counted_base類指標以實現多型。當sp_couted_base類管理的shared_ptr指標引用計數值為0時,會進行shared_ptr儲存指標的刪除操作。但是sp_counted_base類是否要執行delete this還要看weak_ptr,因為weak_ptr的weak_count類中也持有該指標。如果weak_ptr的自身的引用值為0,那麼sp_counted_base類執行delete this,帶著派生類一起銷燬。
相關文章
- shared_ptr原始碼分析原始碼
- HashMap原始碼分析,未完待續HashMap原始碼
- dyld背後的故事&原始碼分析原始碼
- 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原始碼分析原始碼
- 以太坊原始碼分析(3)以太坊交易手續費明細原始碼
- 深度 Mybatis 3 原始碼分析(一)SqlSessionFactoryBuilder原始碼分析MyBatis原始碼SQLSessionUI
- 以太坊原始碼分析(51)rpc原始碼分析原始碼RPC
- [Abp 原始碼分析]十六、後臺作業與後臺工作者原始碼
- Spring Cloud原始碼分析之Eureka篇第七章:續約SpringCloud原始碼
- 【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原始碼