这些类分别是sp_counted_impl_p,sp_counted_impl_pd,sp_counted_impl_pda。
1. sp_counted_impl_p类
<span style="font-size:18px;">template<class X> class sp_counted_impl_p: public sp_counted_base
{
private:
X * px_;
sp_counted_impl_p( sp_counted_impl_p const & );
sp_counted_impl_p & operator= ( sp_counted_impl_p const & );
typedef sp_counted_impl_p<X> this_type;
public:
explicit sp_counted_impl_p( X * px ): px_( px )
{
}
virtual void dispose() // nothrow
{
boost::checked_delete( px_ );
}
virtual void * get_deleter( detail::sp_typeinfo const & )
{
return 0;
}
virtual void * get_untyped_deleter()
{
return 0;
}
#if defined(BOOST_SP_USE_STD_ALLOCATOR)
void * operator new( std::size_t )
{
return std::allocator<this_type>().allocate( 1, static_cast<this_type *>(0) );
}
void operator delete( void * p )
{
std::allocator<this_type>().deallocate( static_cast<this_type *>(p), 1 );
}
#endif
#if defined(BOOST_SP_USE_QUICK_ALLOCATOR)
void * operator new( std::size_t )
{
return quick_allocator<this_type>::alloc();
}
void operator delete( void * p )
{
quick_allocator<this_type>::dealloc( p );
}
#endif
};</span>
这个类比其父类仅仅增加了一个成员变量px_,而且这个类还是一个模板类。
该类也将自己的复制和赋值构造函数声明为私有的,那么我们不能在外面通过其复制和赋值构造函数产生新的对象。
该类有一个带一个参数的构造函数,并且定义为显示的,说明如果类型不匹配,编译的时候编译器会发出警告。这样用来提示可能隐含的编码错误。
sp_counted_base中提到有三个纯虚函数,那么一旦子类继承了sp_counted_base类,那么自然而然就必须实现这三个纯虚函数,否则子类仍然无法创建对象。
在该类中,实现的dispose函数直接调用checked_delete函数,前面提到dispose主要用来通知子类所管理的资源要在这个时候释放,想一想,sp_counted_impl_p管理了什么资源呢,耶,还真有,就是_px,所以我们将_px传递给了checked_delete函数,让checked_delete函数来释放资源,那么checked_delete能否胜任呢,那就来看看其实现细节。
<span style="font-size:18px;">template<class T> inline void checked_delete(T * x)
{
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
(void) sizeof(type_must_be_complete);
delete x;
}</span>
发现checked_delete函数也是一个模板函数,可能很多人会去想为什么会出现typedef char type_must_be_complete[sizeof(T)?1:-1],这是因为由于后面我们通过delete x来销毁x,如果T不是complete type,那么就不能通过delete 直接来直接销毁其对象的指针。
那什么是complete type呢,要弄清楚complete type,首先要知道哪一些是incomplete type,incomplete type主要有三类:
- 无法确定成员的结构体类型,包括class和struct。例如某个类中的某个成员的类型没有定义
- 无法确定成员的联合体类型,union。例如某个union中的某个成员的类型没有定义
- 无法确定大小的数组类型,X[]。例如char a[];
- 申明一个对象,例如在某个地方定义了a数组,那么在两外一个地方可以通过extern char a[]来申明,但是此时无法通过sizeof(a)来获取大小
- 解决类之间的循环依赖,比如一个类定义需要A类型的对象,而A定义的时候需要B类型的对象,这样就形成了循环依赖,这样就可以通过incomplete type,也就是class A;在B定义之前出现
get_untyped_deleter也返回一个空指针。
剩下的就是重载了new和delete函数,根据配置不同分别调用std::allocator<this_type>或者quick_allocator<this_type>中的分配和回收函数。
2. sp_counted_impl_pd类
<span style="font-size:18px;">template<class P, class D> class sp_counted_impl_pd: public sp_counted_base
{
private:
P ptr; // copy constructor must not throw
D del; // copy constructor must not throw
sp_counted_impl_pd( sp_counted_impl_pd const & );
sp_counted_impl_pd & operator= ( sp_counted_impl_pd const & );
typedef sp_counted_impl_pd<P, D> this_type;
public:
sp_counted_impl_pd( P p, D & d ): ptr( p ), del( d )
{
}
sp_counted_impl_pd( P p ): ptr( p ), del()
{
}
virtual void dispose() // nothrow
{
del( ptr );
}
virtual void * get_deleter( detail::sp_typeinfo const & ti )
{
return ti == BOOST_SP_TYPEID(D)? &reinterpret_cast<char&>( del ): 0;
}
virtual void * get_untyped_deleter()
{
return &reinterpret_cast<char&>( del );
}
#if defined(BOOST_SP_USE_STD_ALLOCATOR)
void * operator new( std::size_t )
{
return std::allocator<this_type>().allocate( 1, static_cast<this_type *>(0) );
}
void operator delete( void * p )
{
std::allocator<this_type>().deallocate( static_cast<this_type *>(p), 1 );
}
#endif
#if defined(BOOST_SP_USE_QUICK_ALLOCATOR)
void * operator new( std::size_t )
{
return quick_allocator<this_type>::alloc();
}
void operator delete( void * p )
{
quick_allocator<this_type>::dealloc( p );
}
#endif
};</span>
这个类比sp_counted_impl_p类多了一个模板参数,而第二个模板参数主要用于传递回收资源函数,在sp_counted_impl_p中我们通过checked_delete来释放管理的资源,而这里采用的是通过模板传递进来的del对象。del本身是一个类的对象,在里面通过del(ptr)来回收资源,说明D(来自模板参数)这个类一定重载了()操作符,而主要功能就是用来回收资源。除上述不同外,还有一点不同,get_deleter和get_untyped_deleter不在返回空指针,而是返回del对象的地址。
3. sp_counted_impl_pda类
<span style="font-size:18px;">template<class P, class D, class A> class sp_counted_impl_pda: public sp_counted_base
{
private:
P p_; // copy constructor must not throw
D d_; // copy constructor must not throw
A a_; // copy constructor must not throw
sp_counted_impl_pda( sp_counted_impl_pda const & );
sp_counted_impl_pda & operator= ( sp_counted_impl_pda const & );
typedef sp_counted_impl_pda<P, D, A> this_type;
public:
sp_counted_impl_pda( P p, D & d, A a ): p_( p ), d_( d ), a_( a )
{
}
sp_counted_impl_pda( P p, A a ): p_( p ), d_( a ), a_( a )
{
}
virtual void dispose() // nothrow
{
d_( p_ );
}
virtual void destroy() // nothrow
{
#if !defined( BOOST_NO_CXX11_ALLOCATOR )
typedef typename std::allocator_traits<A>::template rebind_alloc< this_type > A2;
#else
typedef typename A::template rebind< this_type >::other A2;
#endif
A2 a2( a_ );
#if !defined( BOOST_NO_CXX11_ALLOCATOR )
std::allocator_traits<A2>::destroy( a2, this );
#else
this->~this_type();
#endif
a2.deallocate( this, 1 );
}
virtual void * get_deleter( detail::sp_typeinfo const & ti )
{
return ti == BOOST_SP_TYPEID( D )? &reinterpret_cast<char&>( d_ ): 0;
}
virtual void * get_untyped_deleter()
{
return &reinterpret_cast<char&>( d_ );
}
};</span>
这个类相比前两个类,又增加了一个模板参数,用于内存管理
并且复写了父类中的destroy函数,注意父类中的destroy函数是一个虚函数,所以这里体现了多态,凡是sp_counted_impl_pda类的指针对象或者引用都会调用复写之后的destroy函数。
destroy函数实现:
得到标准库中的内存管理对象,并释放this对象。
这三个类是以后分析shared_ptr和weak_ptr的基础。