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

1 篇文章 0 订阅
最近在阅读《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”。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值