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析构时企图删除一个在栈上分配的对象,发生未定义行为。

 

posted @ 2015-12-31 04:58  linux2015  阅读(513)  评论(0编辑  收藏  举报