boost中的智能指针shared_ptr的指针管理

来源:互联网 发布:矩阵潜袭全扩要买哪些 编辑:程序博客网 时间:2024/06/05 00:24
最近在阅读《Beyond the C++ STL》一书的shared_ptr一章时,遇到点困惑,记录如下:

原书44~45页

#include "boost/shared_ptr.hpp" #include <vector> #include <iostream>  class A { public:   virtual void sing()= protected:   virtual ~A() {}; };  class B : public A { public:   virtual void sing() {     std::cout << "Do re mi fa so la";   } };  boost::shared_ptr<A> createA() {   boost::shared_ptr<A> p(new B());   return p; }  int main() {   typedef std::vector<boost::shared_ptr<A> > container_type;   typedef container_type::iterator iterator;    container_type container;   for (int i=0;i<10;++i) {     container.push_back(createA());   }     std::cout << "The choir is gathered: \n";   iterator end=   for (iterator it=container.begin();it!=end;++it) {     (*it)->sing();   } } 

上面的例子示范了一个强有力的技术,它涉及 A里面的 protected 析构函数。因为函数  createA 返回的是  shared_ptr<A>, 因此不可能对 shared_ptr::get返回的指针调用  delete 。这意味着如果为了向某个需要裸指针的函数传送裸指针而从 shared_ptr中取出裸指针的话,它不会由于意外地被删除而导致灾难。那么,又是如何允许  shared_ptr 删除它的对象的呢? 这是因为指针指向的真正类型是  B;而 B的析构函数不是protected 的。这是非常有用的方法,用于给shared_ptr中的对象增加额外的安全性。 


这句话没有看懂,什么叫“指向的真正类型是B”呢?shared_ptr中不是 T *p么?这明明是指向的A啊,为什么说是指向的B呢?


因为A的析构函数为 protected 的,所以 shared_ptr 类必然不能在其析构函数里调用delete来删除它保存的对象。那么 shared_ptr 究竟是怎么删除它的对象的呢?


好奇心驱使我读了boost关于shared_ptr的源码。从头到尾读了一遍后,竟然没有发现 shared_ptr 的析构函数!因此必然不是在 shared_ptr 的析构函数里删除它的对象。那究竟在哪里呢?


下面是我截取的 shared_ptr 类的实现源码,从中可以窥见一斑:


template<class T> class shared_ptr{private:    // Borland 5.5.1 specific workaround    typedef shared_ptr<T> this_type;public:    ......    typedef typename boost::detail::sp_element< T >::type element_type;    ......public:    ......    template<class Y>    explicit shared_ptr( Y * p ): px( p ), pn() // Y must be complete    {        boost::detail::sp_pointer_construct( this, p, pn );    }    ......private:    element_type * px;                 // contained pointer    boost::detail::shared_count pn;    // reference counter};  // shared_ptr

可以看到,在 shared_ptr 的构造函数,首先将Y *p 赋值给了类成员变量 T* px,然后调用了函数boost::detail::sp_pointer_construct()

template< class T, class Y > inline void sp_pointer_construct( boost::shared_ptr< T > * ppx, Y * p, boost::detail::shared_count & pn ){    boost::detail::shared_count( p ).swap( pn );        ......}

boost::detail::sp_pointer_construct()中调用了shared_count()类,该类是用于管理引用计数的,它的构造函数中的参数 是 Y *p

class shared_count{private:    sp_counted_base * pi_;    ......    template<class Y> explicit shared_count( Y * p ): pi_( 0 )    {        try        {            pi_ = new sp_counted_impl_p<Y>( p );        }        catch(...)        {            boost::checked_delete( p );            throw;        }    }    ~shared_count() // nothrow    {        if( pi_ != 0 ) pi_->release();    }    ......};

可以看到,在shared_count的构造函数中,使用 Y *p 构造了一个 sp_counted_impl_p 类,在该类的构造函数中,仅仅是将 指针 Y *p  赋值给了成员变量 px_

class sp_counted_base{    ......public:    ......    void release() // nothrow    {        pthread_mutex_lock( &m_ );        long new_use_count = --use_count_;        pthread_mutex_unlock( &m_ );        if( new_use_count == 0 )        {            dispose();            ......        }    }    virtual void dispose() = 0; // nothrow    ......};template<class X> class sp_counted_impl_p: public sp_counted_base{private:    X * px_;        ......    explicit sp_counted_impl_p( X * px ): px_( px )    {    }    virtual void dispose() // nothrow    {        ......        boost::checked_delete( px_ );......    }    ......};

因此,从上面的代码,我们可以很清楚的知道,类 shared_ptr 中 使用 成员变量 boost::detail::shared_count pn 的 成员变量 sp_counted_base * pi_ 的 成员变量  X * px_ 保存了 类型为 Y 的变量 *p,而类 shared_ptr 的成员变量 element_type * px 仅仅指向了 类型为 Y 的变量 *p。


于是,在 类 shared_ptr 析构时,它调用 类 sp_counted_base 的 release()函数,调用了 类sp_counted_impl_p 的dispose()函数的实现,并最终调用到了 boost::checked_delete( px_ ),而我们知道px_的类型是 Y,这也就是为什么 《Beyond the C++ STL》中说 shared_ptr中 “这是因为指针指向的真正类型是  B”。


原创粉丝点击