Boost--内存管理--(1)智能指针
(一)RAII机制
RAII机制(资源获取即初始化,Resource Acquisition Is Initialization),在使用资源的类的构造函数中申请资源,然后使用,最后在析构函数中释放资源。
如果对象实在创建在栈上(如局部对象),那么RAAII机制会工作正常,当对象生命周期结束时会调用其析构函数来释放资源。但是当对象是在堆上创建时(用new操作符),那么要想析构该对象内存就需要调用delete操作符了。这这方式存在隐患,当我们new了之后忘了delete就会造成内存泄露。
(二)智能指针
boost.smart_ptr库提供了六种智能指针,包括:scoped_ptr、scoped_array、shared_ptr、shared_array、weak_ptr和intrusive_ptr。在使用这些智能指针时,需要模板类型T的析构函数不能抛出异常。
要使用这些智能指针,需要在加入加入文件:
#include <boost/smart_ptr.hpp> //using namespace boost;
(1)scoped_ptr
scoped_ptr包装了new操作符在堆上分配的动态对象,它有严格的所有权,即它包装的对象指针不能转让,一旦scoped_ptr获取了对象的管理权,就无法从它那里取回来。就像它的取名一样,这个智能指针只能在本作用域里使用,不希望被转让。
来看下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; } };
注意:
- 构造函数接收的是new []的结果
- 没有重载*和->操作符;
- 提供了operator[]操作符的重载,可以像普通数组一样使用;
- 没有begin()、end()迭代器。
建议: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析构时企图删除一个在栈上分配的对象,发生未定义行为。