您的位置:首页 > 其它

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

2013-06-26 15:05 447 查看
最近在阅读《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”。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: