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

  • 相关阅读:
    [From 3.1~3.4]
    [From 2.7]简单应用程序部署(程序集打包)
    [From 2.4]C#编译器和程序集链接器(以及一些它们的命令开关)
    [From 2.3]托管PE文件的组成
    [From 1.1~1.2]CLR的执行模型
    项目开发日志:Build AssetBundle——SpriteAtlas(已解惑)
    JDK所有版本下载链接
    Maven
    SEO优化
    Mysql字符集
  • 原文地址:https://www.cnblogs.com/gis-user/p/5090545.html
Copyright © 2011-2022 走看看