C++智能指针之——boost::intrusive_ptr<T>的内部实现

1、概述

      intrusive_ptr类模板存储了一个指向一个引用计数的对象的指针。每一个 intrusive_ptr 实例都会通过对函数 intrusive_ptr_add_ref 的调用来增加引用计数,并将指针作为参数传递给它。同样,当intrusive_ptr实例被销毁时,它会调用intrusive_ptr_release函数;当对象的引用计数为零时,这个函数会销毁对象。要求用户提供这两个函数的正确的实现。

在支持参数依赖性查找的编译器上,intrusive_ptr_add_ref和intrusive_ptr_release应该在与其参数相对应的命名空间中定义;否则,这些定义需要放到命名空间boost中。boost库提供了一个辅助基类模板 intrusive_ref_counter,基于intrusive_ref_counter可以让自己定义的类支持intrusive_ptr。

intrusive_ptr<T>可以隐式转换为intrusive_ptr<U>,只要T*可以隐式转换为U*,这种“向上”的转换很方便,很nice.

2、为什么要使用intrusive_ptr呢?为什么不使用shared_ptr、unique_ptr、scoped_ptr呢?主要原因如下:

1、一些现有的框架或软件已经提供了内嵌引用计数的对象。

2、intrusive_ptr的内存占用与相应的原始指针相同。

3、intrusive_ptr<T>可以从一个任意的T*类型的裸指针构造,可以构造任意多个intrusive_ptr<T>而不会发生重复释放的问题(shared_ptr<T>如果从裸指针构造则会发生重复释放的问题)。

4、作为一般规则,如果并不确定intrusive_ptr比shared_ptr更合适,那么请优先使用shared_ptr,因为intrusive_ptr是对shared_ptr的一种补足。

3、内部实现

intrusive_ptr.hpp

template<class T> class intrusive_ptr
{
private:

    typedef intrusive_ptr this_type;

public:

    typedef T element_type;

    BOOST_CONSTEXPR intrusive_ptr() BOOST_SP_NOEXCEPT : px( 0 )
    {
    }

    intrusive_ptr( T * p, bool add_ref = true ): px( p )
    {
        if( px != 0 && add_ref ) intrusive_ptr_add_ref( px );
    }

    intrusive_ptr( intrusive_ptr<U> const & rhs ) : px( rhs.get() )
    {
        if( px != 0 ) intrusive_ptr_add_ref( px );
    }

    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 );
    }

    template<class U> intrusive_ptr & operator=(intrusive_ptr<U> const & rhs)
    {
        this_type(rhs).swap(*this);
        return *this;
    }


// Move support

#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )

    intrusive_ptr(intrusive_ptr && rhs) BOOST_SP_NOEXCEPT : px( rhs.px )
    {
        rhs.px = 0;
    }

    intrusive_ptr & operator=(intrusive_ptr && rhs) BOOST_SP_NOEXCEPT
    {
        this_type( static_cast< intrusive_ptr && >( rhs ) ).swap(*this);
        return *this;
    }

    template<class U> friend class intrusive_ptr;

    template<class U>
    intrusive_ptr(intrusive_ptr<U> && rhs)

    : px( rhs.px )
    {
        rhs.px = 0;
    }

    template<class U>
    intrusive_ptr & operator=(intrusive_ptr<U> && rhs) BOOST_SP_NOEXCEPT
    {
        this_type( static_cast< intrusive_ptr<U> && >( rhs ) ).swap(*this);
        return *this;
    }

#endif

    intrusive_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()
    {
        this_type().swap( *this );
    }

    void reset( T * rhs )
    {
        this_type( rhs ).swap( *this );
    }

    void reset( T * rhs, bool add_ref )
    {
        this_type( rhs, add_ref ).swap( *this );
    }

    T * get() const BOOST_SP_NOEXCEPT
    {
        return px;
    }

    T * detach() BOOST_SP_NOEXCEPT
    {
        T * ret = px;
        px = 0;
        return ret;
    }

    T & operator*() const BOOST_SP_NOEXCEPT_WITH_ASSERT
    {
        BOOST_ASSERT( px != 0 );
        return *px;
    }

    T * operator->() const BOOST_SP_NOEXCEPT_WITH_ASSERT
    {
        BOOST_ASSERT( px != 0 );
        return px;
    }

// implicit conversion to "bool"
#include <boost/smart_ptr/detail/operator_bool.hpp>

    void swap(intrusive_ptr & rhs) BOOST_SP_NOEXCEPT
    {
        T * tmp = px;
        px = rhs.px;
        rhs.px = tmp;
    }

private:

    T * px;
};

  template<class T, class U>
    bool operator==(intrusive_ptr<T> const & a, intrusive_ptr<U> const & b) noexcept;

  template<class T, class U>
    bool operator!=(intrusive_ptr<T> const & a, intrusive_ptr<U> const & b) noexcept;

  template<class T, class U>
    bool operator==(intrusive_ptr<T> const & a, U * b) noexcept;

  template<class T, class U>
    bool operator!=(intrusive_ptr<T> const & a, U * b) noexcept;

  template<class T, class U>
    bool operator==(T * a, intrusive_ptr<U> const & b) noexcept;

  template<class T, class U>
    bool operator!=(T * a, intrusive_ptr<U> const & b) noexcept;

  template<class T>
    bool operator<(intrusive_ptr<T> const & a, intrusive_ptr<T> const & b) noexcept;

  template<class T> void swap(intrusive_ptr<T> & a, intrusive_ptr<T> & b) noexcept;

  template<class T> T * get_pointer(intrusive_ptr<T> const & p) noexcept;

  template<class T, class U>
    intrusive_ptr<T> static_pointer_cast(intrusive_ptr<U> const & r) noexcept;

  template<class T, class U>
    intrusive_ptr<T> const_pointer_cast(intrusive_ptr<U> const & r) noexcept;

  template<class T, class U>
    intrusive_ptr<T> dynamic_pointer_cast(intrusive_ptr<U> const & r) noexcept;

  template<class E, class T, class Y>
    std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os,
      intrusive_ptr<Y> const & p);
}

从代码可以看出,boost::intrusive_ptr<T>的实现非常之简单,下面做一下简单的解读:

1、T* px;声明一个T类型的裸指针,用于持有指针数据;

2、拷贝构造函数、析构函数是boost::intrusive_ptr<T>的核心函数,分别调用了intrusive_ptr_add_ref()和intrusive_release()函数,实现了引用计数的增加、减少及释放;

3、intrusive_ptr还支持了Move语义;

4、其他的一些函数,如:get、reset、detach为了方便使用;

当然,上面只是一部分的实现,接下来,我们看一下intrusive_ref_counter的实现

/*!
 * \brief Thread unsafe reference counter policy for \c intrusive_ref_counter
 *
 * The policy instructs the \c intrusive_ref_counter base class to implement
 * a reference counter suitable for single threaded use only. Pointers to the same
 * object with this kind of reference counter must not be used by different threads.
 */
struct thread_unsafe_counter
{
    typedef unsigned int type;

    static unsigned int load(unsigned int const& counter) BOOST_SP_NOEXCEPT
    {
        return counter;
    }

    static void increment(unsigned int& counter) BOOST_SP_NOEXCEPT
    {
        ++counter;
    }

    static unsigned int decrement(unsigned int& counter) BOOST_SP_NOEXCEPT
    {
        return --counter;
    }
};

/*!
 * \brief Thread safe reference counter policy for \c intrusive_ref_counter
 *
 * The policy instructs the \c intrusive_ref_counter base class to implement
 * a thread-safe reference counter, if the target platform supports multithreading.
 */
struct thread_safe_counter
{
    typedef boost::detail::atomic_count type;

    static unsigned int load(boost::detail::atomic_count const& counter) BOOST_SP_NOEXCEPT
    {
        return static_cast< unsigned int >(static_cast< long >(counter));
    }

    static void increment(boost::detail::atomic_count& counter) BOOST_SP_NOEXCEPT
    {
        ++counter;
    }

    static unsigned int decrement(boost::detail::atomic_count& counter) BOOST_SP_NOEXCEPT
    {
        return static_cast< unsigned int >(--counter);
    }
};

template< typename DerivedT, typename CounterPolicyT = thread_safe_counter >
class intrusive_ref_counter;

template< typename DerivedT, typename CounterPolicyT >
void intrusive_ptr_add_ref(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_SP_NOEXCEPT;
template< typename DerivedT, typename CounterPolicyT >
void intrusive_ptr_release(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_SP_NOEXCEPT;

/*!
 * \brief A reference counter base class
 *
 * This base class can be used with user-defined classes to add support
 * for \c intrusive_ptr. The class contains a reference counter defined by the \c CounterPolicyT.
 * Upon releasing the last \c intrusive_ptr referencing the object
 * derived from the \c intrusive_ref_counter class, operator \c delete
 * is automatically called on the pointer to the object.
 *
 * The other template parameter, \c DerivedT, is the user's class that derives from \c intrusive_ref_counter.
 */
template< typename DerivedT, typename CounterPolicyT >
class intrusive_ref_counter
{
private:
    //! Reference counter type
    typedef typename CounterPolicyT::type counter_type;
    //! Reference counter
    mutable counter_type m_ref_counter;

public:
    /*!
     * Default constructor
     *
     * \post <tt>use_count() == 0</tt>
     */
    intrusive_ref_counter() BOOST_SP_NOEXCEPT : m_ref_counter(0)
    {
    }

    /*!
     * Copy constructor
     *
     * \post <tt>use_count() == 0</tt>
     */
    intrusive_ref_counter(intrusive_ref_counter const&) BOOST_SP_NOEXCEPT : m_ref_counter(0)
    {
    }

    /*!
     * Assignment
     *
     * \post The reference counter is not modified after assignment
     */
    intrusive_ref_counter& operator= (intrusive_ref_counter const&) BOOST_SP_NOEXCEPT { return *this; }

    /*!
     * \return The reference counter
     */
    unsigned int use_count() const BOOST_SP_NOEXCEPT
    {
        return CounterPolicyT::load(m_ref_counter);
    }

protected:
    /*!
     * Destructor
     */
    BOOST_DEFAULTED_FUNCTION(~intrusive_ref_counter(), {})

    friend void intrusive_ptr_add_ref< DerivedT, CounterPolicyT >(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_SP_NOEXCEPT;
    friend void intrusive_ptr_release< DerivedT, CounterPolicyT >(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_SP_NOEXCEPT;
};

template< typename DerivedT, typename CounterPolicyT >
inline void intrusive_ptr_add_ref(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_SP_NOEXCEPT
{
    CounterPolicyT::increment(p->m_ref_counter);
}

template< typename DerivedT, typename CounterPolicyT >
inline void intrusive_ptr_release(const intrusive_ref_counter< DerivedT, CounterPolicyT >* p) BOOST_SP_NOEXCEPT
{
    if (CounterPolicyT::decrement(p->m_ref_counter) == 0)
        delete static_cast< const DerivedT* >(p);
}

} // namespace sp_adl_block

using sp_adl_block::intrusive_ref_counter;
using sp_adl_block::thread_unsafe_counter;
using sp_adl_block::thread_safe_counter;

} // namespace boost

#if defined(_MSC_VER)
#pragma warning(pop)
#endif

#endif // BOOST_SMART_PTR_INTRUSIVE_REF_COUNTER_HPP_INCLUDED_

上面代码中,有三个最关键的类型,分别是:thread_unsafe_counter、thread_safe_counter和intrusive_ref_counter:

1、两个计数策略:thread_unsafe_counter和thread_safe_counter分别实现了线程不安全的和线程安全的引用计数,内部均有一个引用计数成员——counter,实现了counter的++和--操作;

2、intrusive_ref_counter则通过模板参数,使用了上述的thread_unsafe_counter和thread_safe_counter,在没有指定CounterPolicyT的情况下,默认使用的是thread_safe_counter。

有两个最关键的函数,分别是:intrusive_ptr_add_ref和intrusive_ptr_release:

1、intrusive_ptr_add_ref函数,实现了增加引用计数,在boost::intrusive_ptr<T>的copy constructor中调用;

2、intrusive_ptr_release函数,实现了减少引用计数,当引用计数减少到0的时候,则释放对象;

PS:

1、从上面intrusive_ptr_release函数的代码可以看出,释放对象用的是delete操作符,所以intrusive_ptr不可以持有数组对象,否则会造成内存泄漏。

2、从实现上来看,比shared_ptr的内部实现简单多了,前几年有幸了解过shared_ptr的内部实现,以后有机会把内部实现的原理也讲一下(并不仅仅是简单的引用计数那么简单)。

3、一般情况下,当我们自己定义的class或struct需要支持boost::intrusive_ptr<T>时,只需要从boost::intrusive_ref_counter继承即可,不需要写任何多余的函数,因为boost已经帮我们实现了,示例如下:

class smarter:public boost::intrusive_ref_counter<smarter,boost::thread_safe_counter>
{
public:
    smarter(){}
    virtual ~smarter()=default;

    boost::intrusive_ptr<smarter> self()
    {//此函数仅仅是为了方便的从对象生成intrusive_ptr,比如:从栈对象上生成一个intrusive_ptr
        return boost::intrusive_ptr<smarter>(this);
    }
};

猜你喜欢

转载自blog.csdn.net/lianshaohua/article/details/109289002