(一)RAII機制 ios
RAII機制(資源獲取即初始化,Resource Acquisition Is Initialization),在使用資源的類的構造函數中申請資源,而後使用,最後在析構函數中釋放資源。數組
若是對象實在建立在棧上(如局部對象),那麼RAAII機制會工做正常,當對象生命週期結束時會調用其析構函數來釋放資源。可是當對象是在堆上建立時(用new操做符),那麼要想析構該對象內存就須要調用delete操做符了。這這方式存在隱患,當咱們new了以後忘了delete就會形成內存泄露。less
(二)智能指針函數
boost.smart_ptr庫提供了六種智能指針,包括:scoped_ptr、scoped_array、shared_ptr、shared_array、weak_ptr和intrusive_ptr。在使用這些智能指針時,須要模板類型T的析構函數不能拋出異常。ui
要使用這些智能指針,須要在加入加入文件: this
#include <boost/smart_ptr.hpp> //using namespace boost;
(1)scoped_ptrspa
scoped_ptr包裝了new操做符在堆上分配的動態對象,它有嚴格的全部權,即它包裝的對象指針不能轉讓,一旦scoped_ptr獲取了對象的管理權,就沒法從它那裏取回來。就像它的取名同樣,這個智能指針只能在本做用域裏使用,不但願被轉讓。scala
來看下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_PTR explicit 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 ); #endif boost::checked_delete( px ); } void reset(T * p = 0) // never throws{ BOOST_ASSERT( p == 0 || p != px ); // catch self-reset errors this_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; } #include <boost/smart_ptr/detail/operator_bool.hpp> void swap(scoped_ptr & b) BOOST_NOEXCEPT{ T * tmp = b.px; b.px = px; px = tmp; } };
能夠看到scoped_ptr把複製構造函數和賦值操做符(=)都聲明爲私有的,這樣保證了scoped_ptr的noncopyable,也保證了其管理的指針不能被轉讓。還要注意scoped_ptr沒法比較,由於它的兩個重載比較運算符是私有的。指針
注意:因爲scoped_ptr不能拷貝和賦值,因此它不能做爲容器的元素。
(2)scoped_array
scoped_array很像scoped_ptr,它包裝的是new []和delete []操做。
下面是scoped_ptr的部分源代碼:
template<class T> class scoped_array // noncopyable{ private: T * px; scoped_array(scoped_array const &); scoped_array & operator=(scoped_array const &); typedef scoped_array<T> this_type; void operator==( scoped_array const& ) const; void operator!=( scoped_array const& ) const; public: typedef T element_type; explicit scoped_array( T * p = 0 ) BOOST_NOEXCEPT : px( p ) { #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) boost::sp_array_constructor_hook( px ); #endif } ~scoped_array() // never throws { #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) boost::sp_array_destructor_hook( px ); #endif boost::checked_array_delete( px ); } void reset(T * p = 0) // never throws (but has a BOOST_ASSERT in it, so not marked with BOOST_NOEXCEPT) { BOOST_ASSERT( p == 0 || p != px ); // catch self-reset errors this_type(p).swap(*this); } T & operator[](std::ptrdiff_t i) const // never throws (but has a BOOST_ASSERT in it, so not marked with BOOST_NOEXCEPT) { BOOST_ASSERT( px != 0 ); BOOST_ASSERT( i >= 0 ); return px[i]; } T * get() const BOOST_NOEXCEPT{ return px; } #include <boost/smart_ptr/detail/operator_bool.hpp> void swap(scoped_array & b) BOOST_NOEXCEPT{ T * tmp = b.px; b.px = px; px = tmp; } };
注意:
建議:scoped_ptr的使用仍是有些不靈活,首先它值提供了一個指針的形式,全部在須要使用數組的時候仍是使用std::vector容器代替scoped_ptr比較好。
(3)shared_ptr
shared_ptr也是包裝了new操做符,可是它最重要的一點是它實現了引用計數,因此它能夠被自由的拷貝和賦值,跟其名字同樣是能夠共享的,當沒有代碼使用(即引用計數爲0)時,它才刪除被包裝的動態分配的對象內存。可被當作容器的元素。
如下是它的部分源代碼:
template<class T> class shared_ptr{ private: typedef shared_ptr<T> this_type; public: typedef typename boost::detail::sp_element< T >::type element_type; shared_ptr() BOOST_NOEXCEPT : px( 0 ), pn() {} template<class Y> explicit shared_ptr( Y * p ): px( p ), pn() // Y must be complete {boost::detail::sp_pointer_construct( this, p, pn );} template<class Y, class D> shared_ptr( Y * p, D d ): px( p ), pn( p, d ) {boost::detail::sp_deleter_construct( this, 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 );} template<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 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 ) BOOST_NOEXCEPT : px( r.px ), pn( r.pn ) {boost::detail::sp_assert_convertible< Y, T >();} template< class Y > shared_ptr( shared_ptr<Y> const & r, element_type * p ) BOOST_NOEXCEPT : px( p ), pn( r.pn ) {} template< class Y, class D > shared_ptr( boost::movelib::unique_ptr< Y, D > r ): px( r.get() ), pn(){ boost::detail::sp_assert_convertible< Y, T >(); typename boost::movelib::unique_ptr< Y, D >::pointer tmp = r.get(); pn = boost::detail::shared_count( r ); boost::detail::sp_deleter_construct( this, tmp ); } shared_ptr & operator=( shared_ptr const & r ) BOOST_NOEXCEPT { this_type(r).swap(*this); return *this; } template<class Y, class D> shared_ptr & operator=( boost::movelib::unique_ptr<Y, D> r ) { boost::detail::sp_assert_convertible< Y, T >(); typename boost::movelib::unique_ptr< Y, D >::pointer p = r.get(); shared_ptr tmp; tmp.px = p; tmp.pn = boost::detail::shared_count( r ); boost::detail::sp_deleter_construct( &tmp, p ); tmp.swap( *this ); return *this; } void 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 errors this_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_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 static_cast< typename boost::detail::sp_array_access< T >::type >( 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);} private: template<class Y> friend class shared_ptr; template<class Y> friend class weak_ptr; #endif element_type * px; // contained pointer boost::detail::shared_count pn; // reference counter };
不能使用static_cast<T *>(sp.get())這種形式將shared_ptr管理的指針進行顯示轉換,而shared_ptr也提供了static_pointer_cast<T>()、const_pointer_cast<T>()和dynamic_pointer_cast<T>()幾個對應的成員函數。另外應使用unique(),不適用use_count()==1的形式。
另外在建立shared_ptr的時候可使用工廠函數來建立(make_shared<T>()),它位於文件make_shared.hpp中。使用時須要:
#include <boost/make_shared.hpp>
這是make_shared其中一個實現方式:
template< class T, class... Args > typename boost::detail::sp_if_not_array< T >::type make_shared( Args && ... args ) { boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) ); boost::detail::sp_ms_deleter< T > * pd = static_cast<boost::detail::sp_ms_deleter< T > *>( pt._internal_get_untyped_deleter() ); void * pv = pd->address(); ::new( pv ) T( boost::detail::sp_forward<Args>( args )... ); pd->set_initialized(); T * pt2 = static_cast< T* >( pv ); boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); return boost::shared_ptr< T >( pt, pt2 ); }
注意:關於shared_ptr還有不少知識點。。。
(4)weak_ptr
weak_ptr是爲配合shared_ptr而引入的一種智能指針,不具備普通指針的行爲,它沒有重載operator *和->操做符。用於觀測share_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; 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 copy 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 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 >(); } #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() ) #else weak_ptr( weak_ptr<Y> && r ) #endif 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; } #endif template<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() ) #else weak_ptr( shared_ptr<Y> const & r ) #endif BOOST_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; } #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 shared_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_FRIENDS private: template<class Y> friend class weak_ptr; template<class Y> friend class shared_ptr; #endif element_type * px; // contained pointer boost::detail::weak_count pn; // reference counter }; // weak_ptr
weak_ptr被設計爲與shared_ptr共同工做的,能夠從一個shared_ptr或者另外一個weak_ptr對象構造,獲取資源的觀測權。但weak_ptr沒有共享資源,它的構造不會引發指針引用計數的增長。一樣,在weak_ptr析構時也不會致使引用計數的減小。
使用weak_ptr的成員函數use_count()能夠獲取shared_ptr的引用計數,另外一個expired()的功能等價於use_count()==0,可是更快,表示被觀測的資源已經不存在。
得到this的shared_ptr:
在文件<boost/enable_shared_from_this.hpp>中定義了一個enable_shared_from_this<T>類,它的聲明摘要:
template<class T> class enable_shared_from_this{ protected: enable_shared_from_this() BOOST_NOEXCEPT{ } enable_shared_from_this(enable_shared_from_this const &) BOOST_NOEXCEPT { } enable_shared_from_this & operator=(enable_shared_from_this const &) BOOST_NOEXCEPT { return *this; } ~enable_shared_from_this() BOOST_NOEXCEPT { } public: 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; } weak_ptr<T> weak_from_this() BOOST_NOEXCEPT { return weak_this_; } weak_ptr<T const> weak_from_this() const BOOST_NOEXCEPT { return weak_this_; } public: // actually private, but avoids compiler template friendship issues // 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 ); } } private: mutable weak_ptr<T> weak_this_; };
在使用的時候只須要讓想被shared_ptr管理的類繼承自enable_shared_from_this,調用成員函數shared_form_this()會返回this的shared_ptr。例如:
#include <boost/enable_shared_from_this.hpp> #include <boost/make_shared.hpp> #include <iostream> class self_shared : public boost::enable_shared_from_this<self_shared>{ public: self_shared(int n) : x(n) { } int x; void print(){ std::cout<<"self_shared:"<<x<<std::endl; } }; int main(int argc,char * argv[]){ std::shared_ptr<self_shared> sp=std::make_shared<self_shared>(123); sp->print(); std::shared_ptr<self_shared> p=sp->shared_from_this(); p->x=100; p->print(); return 0; }
要注意的是:千萬不能從一個普通的對象(self_shared對象)使用shared_from_this()獲取shared_ptr,例如:
self_shared ss;
boost::shared_ptr<self_shared> p=ss.shared_from_this();
這個在程序運行時會致使shared_ptr析構時企圖刪除一個在棧上分配的對象,發生未定義行爲。