weak_ptr原始碼分析
之前分析了shared_ptr的框架,這次來說一下shared_ptr的兄弟weak_ptr,它們常常是一起出現的。
weak_ptr顧名思義就是弱指標,它不會增加物件的引用計數,欸有過載operator*和operator->,使用時,應當通過weak_ptr的lock函式構造一個shared_ptr。
作用:防止迴圈引用(以後部落格分析)。應用:在enable_shared_from_this類中,它有一個weak_ptr weak_this_成員。當物件構造完成後,在類成員函式內部可以呼叫shared_from_this獲得該物件自身型別的shared_ptr。千萬不要在建構函式裡呼叫share_from_this,因為this還沒有完全構造出來,此時無法根據this構造一個正確的weak_ptr。
weak_ptr原始碼
template<class T> class weak_ptr
{
private:
// Borland 5.5.1 specific workarounds
typedef weak_ptr<T> this_type;
public:
typedef typename boost::detail::sp_element< T >::type element_type;
//pn是weak_count,而不是shared_count,所以weak_ptr不會引起指標引用計數增加。
weak_ptr() BOOST_NOEXCEPT : px(0), pn() // never throws in 1.30+
{
}
// generated copy constructor, assignment, destructor are fine...
//如果 定義"BOOST沒有右值引用" 為假
#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
// ... except in C++0x, move disables the implicit copy
//支援copy assignment
weak_ptr( weak_ptr const & r ) BOOST_NOEXCEPT : px( r.px ), pn( r.pn )
{
}
weak_ptr & operator=( weak_ptr const & r ) BOOST_NOEXCEPT
{
px = r.px;
pn = r.pn;
return *this;
}
#endif
//
// The "obvious(明顯的)" converting constructor implementation:
//
// template<class Y>
// weak_ptr(weak_ptr<Y> const & r): px(r.px), pn(r.pn) // never throws
// {
// }
//
// has a serious problem.
//
// r.px may already have been invalidated(使無效). The px(r.px)
// conversion may require(需要) access to *r.px (virtual inheritance).
//
// It is not possible to avoid spurious(假的,偽造的) access violations since
// in multithreaded programs r.px may be invalidated at any point.
//
template<class Y>
#if !defined( BOOST_SP_NO_SP_CONVERTIBLE )
weak_ptr( weak_ptr<Y> const & r, typename boost::detail::sp_enable_if_convertible<Y,T>::type = boost::detail::sp_empty() )
#else
weak_ptr( weak_ptr<Y> const & r )
#endif
BOOST_NOEXCEPT : px(r.lock().get()), pn(r.pn)
{
boost::detail::sp_assert_convertible< Y, T >();
}
template<class Y>
weak_ptr( weak_ptr<Y> && r ) BOOST_NOEXCEPT : px( r.lock().get() ), pn( static_cast< boost::detail::weak_count && >( r.pn ) ) //強轉為右值
{
boost::detail::sp_assert_convertible< Y, T >();
r.px = 0;
}
// for better efficiency in the T == Y case
weak_ptr( weak_ptr && r )
BOOST_NOEXCEPT : px( r.px ), pn( static_cast< boost::detail::weak_count && >( r.pn ) )
{
r.px = 0;
}
// for better efficiency in the T == Y case
weak_ptr & operator=( weak_ptr && r ) BOOST_NOEXCEPT
{
this_type( static_cast< weak_ptr && >( r ) ).swap( *this );
return *this;
}
template<class Y>
weak_ptr( shared_ptr<Y> const & r )
BOOST_NOEXCEPT : px( r.px ), pn( r.pn ) //重點weak_ptr的pn=shared_ptr的pn,也就是說weak_count=shared_count
{
boost::detail::sp_assert_convertible< Y, T >();
}
#if !defined(BOOST_MSVC) || (BOOST_MSVC >= 1300)
template<class Y>
weak_ptr & operator=( weak_ptr<Y> const & r ) BOOST_NOEXCEPT
{
boost::detail::sp_assert_convertible< Y, T >();
px = r.lock().get();
pn = r.pn;
return *this;
}
#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
template<class Y>
weak_ptr & operator=( weak_ptr<Y> && r ) BOOST_NOEXCEPT
{
this_type( static_cast< weak_ptr<Y> && >( r ) ).swap( *this );
return *this;
}
#endif
template<class Y>
weak_ptr & operator=( shared_ptr<Y> const & r ) BOOST_NOEXCEPT
{
boost::detail::sp_assert_convertible< Y, T >();
px = r.px;
pn = r.pn;
return *this;
}
#endif
//將weak_ptr提升為shared_ptr,如果已經過期,則返回一個空shared_ptr
shared_ptr<T> lock() const BOOST_NOEXCEPT
{
return shared_ptr<T>( *this, boost::detail::sp_nothrow_tag() ); //呼叫shared_ptr(const weak_ptr<T>& r, sp_nothrow_tag());
}
//返回shared_ptr的引用計數,pn是weak_count型別,但是它實際上轉調它持有的sp_counted_base指標(和shared_ptr持有同一個)的use_count()函式,所以可以返回所有shared_ptr引用計數的相關資訊,下同。
long use_count() const BOOST_NOEXCEPT
{
return pn.use_count();
}
//判斷shared_ptr是否過期,也就是引用計數是否為0,如果為0,說明shared_ptr已經過期死了,返回true
bool expired() const BOOST_NOEXCEPT
{
return pn.use_count() == 0;
}
bool _empty() const // extension, not in std::weak_ptr
{
return pn.empty();
}
void reset() BOOST_NOEXCEPT // never throws in 1.30+
{
this_type().swap(*this);
}
void swap(this_type & other) BOOST_NOEXCEPT
{
std::swap(px, other.px);
pn.swap(other.pn);
}
template<typename Y>
void _internal_aliasing_assign(weak_ptr<Y> const & r, element_type * px2)
{
px = px2;
pn = r.pn;
}
template<class Y> bool owner_before( weak_ptr<Y> const & rhs ) const BOOST_NOEXCEPT
{
return pn < rhs.pn;
}
template<class Y> bool owner_before( shared_ptr<Y> const & rhs ) const BOOST_NOEXCEPT
{
return pn < rhs.pn;
}
下面是weak_count的原始碼:
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;
}
}
值得注意的是,weak_ptr自身也是引用計數型智慧指標,也有引用計數。weak_ptr也支援拷貝分配之類的函式。
上面程式碼最後的這兩個函式是shared_count類的建構函式之一,這是使用weak_ptr的lock函式底層要呼叫的之一。lock函式是使用weak_ptr構造shared_ptr,這回撥用shared_ptr的weak_ptr構造方法,然後shared_ptr的成員shread_count自然也要呼叫以weak_ptr為引數的構造方法。並且由於lock提升這個操作有多執行緒併發的可能,所以這裡呼叫的不是sp_counted_base函式的add_ref_copy(該函式是原子的,但功能簡單,不能說明提升成功或失敗),而是add_ref_lock函式,gcc版本是這樣實現的:
inline int atomic_conditional_increment( int * pw )
{
spinlock_pool<1>::scoped_lock lock( pw );
int rv = *pw;
if( rv != 0 ) ++*pw;
return rv;
}
首先對pw的記憶體進行上鎖,然後再進行相應操作。如果*pw不為0,則weak_ptr提升成功,增加引用計數。如果為0,說明shared_ptr物件已死,不能提升,不增加引用計數,返回0。在shared_count建構函式中(就是上面那個),取消pi_的賦值(不打算指向weak_ptr的sp_counted_base),將它重新賦為空。
如此一來,便可實現weak_ptr提升稱為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原始碼分析原始碼
- 原始碼分析——HashMap原始碼HashMap