boost智能指针之shared_ptr,scoped_ptr,intrusive_ptr,weak_ptr源码简析
boost庫實現(xiàn)了各種智能指針,基本上都納入了c++11標(biāo)準(zhǔn)中,boost庫的smart_ptr目錄下就是各種指針的實現(xiàn)了:
1.shared_ptr
template<class T> class shared_ptr { private:// Borland 5.5.1 specific workaroundtypedef shared_ptr<T> this_type;public:typedef typename boost::detail::sp_element< T >::type element_type;shared_ptr() BOOST_NOEXCEPT : px( 0 ), pn() // never throws in 1.30+{}#if !defined( BOOST_NO_CXX11_NULLPTR )shared_ptr( boost::detail::sp_nullptr_t ) BOOST_NOEXCEPT : px( 0 ), pn() // never throws{}#endiftemplate<class Y>explicit shared_ptr( Y * p ): px( p ), pn() // Y must be complete{boost::detail::sp_pointer_construct( this, p, pn );}//// 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 );}#if !defined( BOOST_NO_CXX11_NULLPTR )template<class D> shared_ptr( boost::detail::sp_nullptr_t p, D d ): px( p ), pn( p, d ){}#endif// 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 );}#if !defined( BOOST_NO_CXX11_NULLPTR )template<class D, class A> shared_ptr( boost::detail::sp_nullptr_t p, D d, A a ): px( p ), pn( p, d, a ){}#endif// generated copy constructor, destructor are fine...#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )// ... except in C++0x, move disables the implicit copyshared_ptr( shared_ptr const & r ) BOOST_NOEXCEPT : px( r.px ), pn( r.pn ){}#endiftemplate<class Y>explicit shared_ptr( weak_ptr<Y> const & r ): pn( r.pn ) // may throw{boost::detail::sp_assert_convertible< Y, T >();// it is now safe to copy r.px, as pn(r.pn) did not throwpx = 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> #if !defined( BOOST_SP_NO_SP_CONVERTIBLE )shared_ptr( shared_ptr<Y> const & r, typename boost::detail::sp_enable_if_convertible<Y,T>::type = boost::detail::sp_empty() )#elseshared_ptr( shared_ptr<Y> const & r )#endifBOOST_NOEXCEPT : px( r.px ), pn( r.pn ){boost::detail::sp_assert_convertible< Y, T >();}// aliasingtemplate< class Y >shared_ptr( shared_ptr<Y> const & r, element_type * p ) BOOST_NOEXCEPT : px( p ), pn( r.pn ){}#ifndef BOOST_NO_AUTO_PTRtemplate<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_RVALUE_REFERENCES )template<class Y>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 );}#elif !defined( BOOST_NO_SFINAE ) && !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION )template<class Ap>explicit shared_ptr( Ap r, typename boost::detail::sp_enable_if_auto_ptr<Ap, int>::type = 0 ): px( r.get() ), pn(){typedef typename Ap::element_type Y;boost::detail::sp_assert_convertible< Y, T >();Y * tmp = r.get();pn = boost::detail::shared_count( r );boost::detail::sp_deleter_construct( this, tmp );}#endif // BOOST_NO_SFINAE, BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION#endif // BOOST_NO_AUTO_PTR#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// assignmentshared_ptr & operator=( shared_ptr const & r ) BOOST_NOEXCEPT{this_type(r).swap(*this);return *this;}#if !defined(BOOST_MSVC) || (BOOST_MSVC >= 1400)template<class Y>shared_ptr & operator=(shared_ptr<Y> const & r) BOOST_NOEXCEPT{this_type(r).swap(*this);return *this;}#endif#ifndef BOOST_NO_AUTO_PTRtemplate<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;}#elif !defined( BOOST_NO_SFINAE ) && !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION )template<class Ap>typename boost::detail::sp_enable_if_auto_ptr< Ap, shared_ptr & >::type operator=( Ap r ){this_type( r ).swap( *this );return *this;}#endif // BOOST_NO_SFINAE, BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION#endif // BOOST_NO_AUTO_PTR#if !defined( BOOST_NO_CXX11_SMART_PTR ) && !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )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#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )shared_ptr( shared_ptr && r ) BOOST_NOEXCEPT : px( r.px ), pn(){pn.swap( r.pn );r.px = 0;}template<class Y> #if !defined( BOOST_SP_NO_SP_CONVERTIBLE )shared_ptr( shared_ptr<Y> && r, typename boost::detail::sp_enable_if_convertible<Y,T>::type = boost::detail::sp_empty() )#elseshared_ptr( shared_ptr<Y> && r )#endifBOOST_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;}template<class Y>shared_ptr & operator=( shared_ptr<Y> && r ) BOOST_NOEXCEPT{this_type( static_cast< shared_ptr<Y> && >( r ) ).swap( *this );return *this;}#endif#if !defined( BOOST_NO_CXX11_NULLPTR )shared_ptr & operator=( boost::detail::sp_nullptr_t ) BOOST_NOEXCEPT // never throws{this_type().swap(*this);return *this;}#endifvoid reset() BOOST_NOEXCEPT // never throws in 1.30+{this_type().swap(*this);}template<class Y> void reset( Y * p ) // Y must be complete{BOOST_ASSERT( p == 0 || p != px ); // catch self-reset errorsthis_type( p ).swap( *this );}template<class Y, class D> void reset( Y * p, D d ){this_type( p, d ).swap( *this );}template<class Y, class D, class A> void reset( Y * p, D d, A a ){this_type( p, d, a ).swap( *this );}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>bool unique() const BOOST_NOEXCEPT{return pn.unique();}long use_count() const BOOST_NOEXCEPT{return pn.use_count();}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();}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)#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDSprivate:template<class Y> friend class shared_ptr;template<class Y> friend class weak_ptr;#endifelement_type * px; // contained pointerboost::detail::shared_count pn; // reference counter}; // shared_ptr可以看到里面的兩個成員變量: element_type * px; // contained pointer boost::detail::shared_count pn; // reference counterpx用于保存原始指針,pn用于指針引用計數(shù),構(gòu)造函數(shù)和賦值運算符都是public,表示可以由shared_ptr構(gòu)造、賦值,大部分情況下使用這個了,唯一缺點是兩個類都用對方成員變量shared_ptr時,由于循環(huán)引用,使得引用計數(shù)無法減為0導(dǎo)致智能指針無法釋放。
2.weak_ptr
template<class T> class weak_ptr { private:// Borland 5.5.1 specific workaroundstypedef weak_ptr<T> this_type;public:typedef typename boost::detail::sp_element< T >::type element_type;weak_ptr() BOOST_NOEXCEPT : px(0), pn() // never throws in 1.30+{}// generated copy constructor, assignment, destructor are fine...#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )// ... except in C++0x, move disables the implicit copyweak_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() )#elseweak_ptr( weak_ptr<Y> const & r )#endifBOOST_NOEXCEPT : px(r.lock().get()), pn(r.pn){boost::detail::sp_assert_convertible< Y, T >();}#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )template<class Y> #if !defined( BOOST_SP_NO_SP_CONVERTIBLE )weak_ptr( weak_ptr<Y> && r, typename boost::detail::sp_enable_if_convertible<Y,T>::type = boost::detail::sp_empty() )#elseweak_ptr( weak_ptr<Y> && r )#endifBOOST_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 caseweak_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 caseweak_ptr & operator=( weak_ptr && r ) BOOST_NOEXCEPT{this_type( static_cast< weak_ptr && >( r ) ).swap( *this );return *this;}#endiftemplate<class Y> #if !defined( BOOST_SP_NO_SP_CONVERTIBLE )weak_ptr( shared_ptr<Y> const & r, typename boost::detail::sp_enable_if_convertible<Y,T>::type = boost::detail::sp_empty() )#elseweak_ptr( shared_ptr<Y> const & r )#endifBOOST_NOEXCEPT : px( r.px ), pn( r.pn ){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;}#endiftemplate<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;}#endifshared_ptr<T> lock() const BOOST_NOEXCEPT{return shared_ptr<T>( *this, boost::detail::sp_nothrow_tag() );}long use_count() const BOOST_NOEXCEPT{return pn.use_count();}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;}// Tasteless as this may seem, making all members public allows member templates // to work in the absence of member template friends. (Matthew Langston)#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDSprivate:template<class Y> friend class weak_ptr;template<class Y> friend class shared_ptr;#endifelement_type * px; // contained pointerboost::detail::weak_count pn; // reference counter}; // weak_ptr還是2個成員變量: template<class Y> friend class weak_ptr; template<class Y> friend class shared_ptr;與shared_ptr不同的是引用計數(shù)的類型為weak_count,在detail里面的表示引用計數(shù)使用detail里面的弱引用實現(xiàn),表示通過shared_ptr構(gòu)造時不修改引用計數(shù),適用循環(huán)引用的情況,一般作為shared_ptr出現(xiàn)循環(huán)引用的情況補充。
3.scoped_ptr
template<class T> class scoped_ptr // noncopyable { private:T * px;scoped_ptr(scoped_ptr const &);scoped_ptr & operator=(scoped_ptr const &);typedef scoped_ptr<T> this_type;void operator==( scoped_ptr const& ) const;void operator!=( scoped_ptr const& ) const;public:typedef T element_type;explicit scoped_ptr( T * p = 0 ): px( p ) // never throws{ #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)boost::sp_scalar_constructor_hook( px ); #endif}#ifndef BOOST_NO_AUTO_PTRexplicit scoped_ptr( std::auto_ptr<T> p ) BOOST_NOEXCEPT : px( p.release() ){ #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)boost::sp_scalar_constructor_hook( px ); #endif}#endif~scoped_ptr() // never throws{ #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)boost::sp_scalar_destructor_hook( px ); #endifboost::checked_delete( px );}void reset(T * p = 0) // never throws{BOOST_ASSERT( p == 0 || p != px ); // catch self-reset errorsthis_type(p).swap(*this);}T & operator*() const // never throws{BOOST_ASSERT( px != 0 );return *px;}T * operator->() const // never throws{BOOST_ASSERT( px != 0 );return px;}T * get() const BOOST_NOEXCEPT{return px;}// implicit conversion to "bool" #include <boost/smart_ptr/detail/operator_bool.hpp>void swap(scoped_ptr & b) BOOST_NOEXCEPT{T * tmp = b.px;b.px = px;px = tmp;} };與上面不同的是,只有一個成員保存原始指針的成員px,表明它不支持引用計數(shù): T * px;
拷貝構(gòu)造和賦值都是private,說明禁止指針復(fù)制和拷貝構(gòu)造 private:T * px;scoped_ptr(scoped_ptr const &);scoped_ptr & operator=(scoped_ptr const &);typedef scoped_ptr<T> this_type;void operator==( scoped_ptr const& ) const;void operator!=( scoped_ptr const& ) const;
4.intrusive_ptr
template<class T> class intrusive_ptr { private:typedef intrusive_ptr this_type;public:typedef T element_type;intrusive_ptr() BOOST_NOEXCEPT : px( 0 ){}intrusive_ptr( T * p, bool add_ref = true ): px( p ){if( px != 0 && add_ref ) intrusive_ptr_add_ref( px );}#if !defined(BOOST_NO_MEMBER_TEMPLATES) || defined(BOOST_MSVC6_MEMBER_TEMPLATES)template<class U> #if !defined( BOOST_SP_NO_SP_CONVERTIBLE )intrusive_ptr( intrusive_ptr<U> const & rhs, typename boost::detail::sp_enable_if_convertible<U,T>::type = boost::detail::sp_empty() )#elseintrusive_ptr( intrusive_ptr<U> const & rhs )#endif: px( rhs.get() ){if( px != 0 ) intrusive_ptr_add_ref( px );}#endifintrusive_ptr(intrusive_ptr const & rhs): px( rhs.px ){if( px != 0 ) intrusive_ptr_add_ref( px );}~intrusive_ptr(){if( px != 0 ) intrusive_ptr_release( px );}#if !defined(BOOST_NO_MEMBER_TEMPLATES) || defined(BOOST_MSVC6_MEMBER_TEMPLATES)template<class U> intrusive_ptr & operator=(intrusive_ptr<U> const & rhs){this_type(rhs).swap(*this);return *this;}#endif// Move support#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )intrusive_ptr(intrusive_ptr && rhs) BOOST_NOEXCEPT : px( rhs.px ){rhs.px = 0;}intrusive_ptr & operator=(intrusive_ptr && rhs) BOOST_NOEXCEPT{this_type( static_cast< intrusive_ptr && >( rhs ) ).swap(*this);return *this;}#endifintrusive_ptr & operator=(intrusive_ptr const & rhs){this_type(rhs).swap(*this);return *this;}intrusive_ptr & operator=(T * rhs){this_type(rhs).swap(*this);return *this;}void reset() BOOST_NOEXCEPT{this_type().swap( *this );}void reset( T * rhs ){this_type( rhs ).swap( *this );}T * get() const BOOST_NOEXCEPT{return px;}T & operator*() const{BOOST_ASSERT( px != 0 );return *px;}T * operator->() const{BOOST_ASSERT( px != 0 );return px;}// implicit conversion to "bool" #include <boost/smart_ptr/detail/operator_bool.hpp>void swap(intrusive_ptr & rhs) BOOST_NOEXCEPT{T * tmp = px;px = rhs.px;rhs.px = tmp;}private:T * px; };依然只有保存原始指針的成員變量,沒有引用計數(shù)的成員變量,不過里面出現(xiàn)了兩個類中沒有定義的函數(shù): intrusive_ptr(intrusive_ptr const & rhs): px( rhs.px ){if( px != 0 ) intrusive_ptr_add_ref( px );}~intrusive_ptr(){if( px != 0 ) intrusive_ptr_release( px );}intrusive_ptr_add_ref( T * )和intrusive_ptr_release(T * )都作用于用戶原始指針,用戶要在兩個函數(shù)中實現(xiàn)引用計數(shù)以及指針的銷毀,找了一下網(wǎng)上作為友元函數(shù)的實現(xiàn): friend void intrusive_ptr_add_ref(intrusive_ptr_base<T> const* s) { // 下面代碼只是為了演示 std::cout << " intrusive_ptr_add_ref... " << std::endl; // 判斷合法性并自增 assert(s != 0); assert(s->ref_count >= 0); ++s->ref_count; } // 遞增引用計數(shù) // 用友元函數(shù)的方式來實現(xiàn),避免了函數(shù)指針類型的轉(zhuǎn)換 // 例如: // template<typename T> void intrusive_ptr_release(T* t) // { // T->release(); // 此處需要定義T的原型 // } friend void intrusive_ptr_release(intrusive_ptr_base<T> const* s) { // 下面代碼只是為了演示 std::cout << " intrusive_ptr_release... " << std::endl; // 判斷合法性并自減 assert(s != 0); assert(s->ref_count >= 0); if (--s->ref_count == 0) { // 進(jìn)行靜態(tài)類型檢查,防止出錯 boost::checked_delete(static_cast<T const*>(s)); } }
智能指針的幾個參考資料
http://www.cnblogs.com/sld666666/archive/2010/12/16/1908265.html
http://blog.csdn.net/callmeback/article/details/7729251
http://blog.csdn.net/yockie/article/details/8840205
http://blog.csdn.net/lanxuezaipiao/article/details/41603883
http://blog.csdn.net/e5max/article/details/50569305
http://blog.csdn.net/lollipop_jin/article/details/8499530
http://blog.csdn.net/liufei_learning/article/details/34808549
http://blog.csdn.net/lwbeyond/article/details/6202256/
總結(jié)
以上是生活随笔為你收集整理的boost智能指针之shared_ptr,scoped_ptr,intrusive_ptr,weak_ptr源码简析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: boost之对象池使用实例
- 下一篇: Visual Studio 2017开发