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