C++boost库中sp_counted_impl_x实现解析

2 篇文章 0 订阅
2 篇文章 0 订阅

sp_counted_impl_x是一系列的类,这些类都是sp_counted_base的子类,

这些类分别是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[];
当然,除了上面三种之外的都是complete type。
incomplete type用来定义对象都会让编译器出现错误,例如char a[],编译器会给出无法确定a大小的错误。
那么既然incomplete type会让编译器报出错误,它的存在有何用处呢?
  • 申明一个对象,例如在某个地方定义了a数组,那么在两外一个地方可以通过extern char a[]来申明,但是此时无法通过sizeof(a)来获取大小
  • 解决类之间的循环依赖,比如一个类定义需要A类型的对象,而A定义的时候需要B类型的对象,这样就形成了循环依赖,这样就可以通过incomplete type,也就是class A;在B定义之前出现
而且只有complete type才能够通过sizeof来确定大小,否则编译器会产生警告,这样可以防止用checked_delete来释放incomplete type类型的资源。

get_deleter函数,获取析构方法,由于这里没有,故返回一个空指针。

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的基础。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值