智能指针源码分析(2)——shared_ptr

上一篇:https://blog.csdn.net/qq_41345173/article/details/104270431
BOOST库源码分享,百度网盘提取码:snuc

1.简介

毫无疑问shared_ptr才是最受欢迎的智能指针也是像普通指针的智能指针。常常听说其内部实现是基于引用计数的那么什么是引用计数,其在内部又是怎样实现的今天就让咋来见识一下它的源码,在此之前,先贴一个来自http://www.cplusplus.com/reference/网站的shared_ptr的例子熟悉一下他的具体用法:

#include <iostream>
#include <memory>
#include <boost/shared_ptr.hpp>
using namespace boost;
using namespace std;
int main () {
  shared_ptr<int> foo;
  shared_ptr<int> bar (new int);

  cout << "foo unique?\n" << std::boolalpha;
  //boolalpha:一个函数指明以后逻辑真打印为true,否则打印为false
  cout << "1: " << foo.unique() << '\n';  // false (empty)

  foo = bar;
  cout << "2: " << foo.unique() << '\n';  // false (shared with bar)

  bar.reset();
  cout << "3: " << foo.unique() << '\n';  // true

  return 0;
}

输出:
foo unique?
1: false
2: false
3: true
需要特别注意的是shared_ptr由于支持拷贝操作,故可以将他安全的放在标准容器里面了

2.源码分析
template<class T> class shared_ptr
{/*boost\smart_ptr\shared_ptr.hpp*/
private:
    typedef shared_ptr<T> this_type;
    element_type * px;                 // contained pointer,element_type等价于类型T
    boost::detail::shared_count pn;    // reference counter
    ...
};  // shared_ptr

码量过于巨大,先来康一康私有成员,毕竟成员函数都是围绕着他们转的呀!重点关注引用计数的数据成员shared_count pn,其私有成员定义如下:

class shared_count
{//boost\smart_ptr\detail\shared_count.hpp
private:
    sp_counted_base * pi_;  //重点在sp_counted_base类
    ...
public:
    shared_count(): pi_(0) {}

继续向下走关注shared_count的私有成员变量sp_counted_base:

class sp_counted_base
{
private:
    sp_counted_base( sp_counted_base const & );
    sp_counted_base & operator= ( sp_counted_base const & );
    int use_count_;        // #shared
    int weak_count_;       // #weak + (#shared != 0)
public:
    sp_counted_base(): use_count_( 1 ), weak_count_( 1 ){}//该类唯一构造函数
    ...

至此已大致清楚了点,若要使用shared_ptr管理资源,根据C++在类中调用构造函数的顺序可知先调用sp_counted_base的构造函数它将成员变量use_count_初始化为1,但是它什么时候调用哩,shared_count的构造函数有多个首先应该调用哪一个哩?以最平常的shared_ptr的构造函数来看:

    template<class Y>
    explicit shared_ptr( Y * p ): px( p ), pn() // Y must be complete
    {
        boost::detail::sp_pointer_construct( this, p, pn );
    }
    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 );
        ...
    }

显然在这个构造函数里面sp_pointer_construct会调用shared_count的构造函数以new出来的指针为参数创建一个临时的shared_count对象,在如下shared_count的构造函数里面会调用sp_counted_impl_p类的构造函数new出来一个sp_counted_impl_p对象用于初始化pi_成员:

    template<class Y> explicit shared_count( Y * p ): pi_( 0 ) {
        pi_ = new sp_counted_impl_p<Y>( p );
		...
    }

瞅一瞅sp_counted_impl_p的构造函数:

template<class X> class sp_counted_impl_p: public sp_counted_base
{
private:
    X * px_;
    ...
public:
    explicit sp_counted_impl_p( X * px ): px_( px ){}
    ...

追踪代码发现sp_counted_impl_p是sp_counted_base的公有派生类,它的自定义私有成员如上,其构造函数仅仅就是用上面的p初始化这个px_,需要注意的是它也会调用基类的构造函数,即刚开始说的sp_counted_base的构造函数初始化use_count_为1。至此这个临时的shared_count以及构造出来了,下一步sp_pointer_construct函数会调用这个临时对象的swap函数,这样就意味着shared_ptr里面的shared_count成员至此完成了自身的构造啦。

3.实现自己的shared_ptr

总结起来就是说先调用shared_ptr对象的构造函数,然后会调用成员变量pn的构造函数初始化它,不过在具体实现的时候略有技巧,下面就仿照上面的流程自己构造一个shared_ptr的基本框架:

#include <iostream>
#include <memory>
#include <string>
using namespace std;

class sp_counted_base
{
private:
    sp_counted_base( sp_counted_base const & );
    sp_counted_base & operator= ( sp_counted_base const & );
    long use_count_;        // #shared
public:
    sp_counted_base(): use_count_( 1 ){}//该类唯一构造函数
    virtual ~sp_counted_base(){
    	//cout<<"sp_counted_base destroy ..."<<endl;
    }
    virtual void dispose() = 0;
    void release() {
    	if(--use_count_==0)
    	{
			dispose();
		}
    }
    long use_count() const // nothrow
    {
        return static_cast<long>( use_count_ );
    }
    void add_ref_copy()
    {
        ++use_count_;
    }
};

template<class X> class sp_counted_impl_p: public sp_counted_base
{
private:
    X * px_;
public:
    explicit sp_counted_impl_p( X * px ): px_( px ){}
    virtual ~sp_counted_impl_p(){
    	//cout<<"sp_counted_impl_p destroy ..."<<endl;
    }
    void dispose(){
    	delete px_;
    	delete this;
    }
};

template<class T> class shared_count
{
private:
    sp_counted_base * pi_; 
public:
	shared_count(T *p):pi_(new sp_counted_impl_p<T>(p)){}
	~shared_count(){
		if(pi_!=0){
			pi_->release();
		}
		//cout<<"shared_count destroy ..."<<endl;
	}
	shared_count(shared_count const& r):pi_(r.pi_){
		if(pi_){
			pi_->add_ref_copy();
		}
	}
	long use_count(){
		return pi_!=0?pi_->use_count():0;
	}
	void swap(shared_count & r){
		sp_counted_base *tmp = r.pi_;
		r.pi_ = pi_;
		pi_ = tmp;
	}
};

template<class T> class shared_ptr
{
private:
    typedef shared_ptr<T> this_type;
    T * px;                 
    shared_count<T>  pn;    // reference counter
public:
    shared_ptr(T *p):px(p),pn(p){}
    ~shared_ptr(){
    	//cout<<"shared_ptr destroy ..."<<endl;
    }
    shared_ptr(shared_ptr const &r):px(r.px),pn(r.pn){}
    long use_count(){
    	return pn.use_count();
    }
    void swap( shared_ptr & other ) 
    {
        std::swap(px, other.px);
        pn.swap(other.pn);
    }
    T & operator* ()const{
    	return *px;
    }
    shared_ptr<T>& operator=(shared_ptr<T> const& r){
    	if(this!=&r){
    		this_type(r).swap(*this);//巧妙的借助临时对象删除了前面的this对象
    	}
    	return *this;
    }
};  // shared_ptr

int main () {
  shared_ptr<string> foo (new string("Hello World!"));
  shared_ptr<string> bar (new string("I'm hero!"));
  cout << "foo and bar\n" ;
  cout<<"foo_str: "<<*foo<<";  bar_str: "<<*bar<<endl;
  cout<<"foo_use_count: "<<foo.use_count()<<";	bar_use_count: "<<bar.use_count()<<endl;
  foo.swap(bar);
  cout<<"foo_str: "<<*foo<<";  bar_str: "<<*bar<<endl;
  foo = bar;
  cout<<"foo_str: "<<*foo<<";  bar_str: "<<*bar<<endl;
  cout<<"foo_use_count: "<<foo.use_count()<<";	bar_use_count: "<<bar.use_count()<<endl;
  return 0;
}

输出:

foo and bar
foo_str: Hello World!;  bar_str: I'm hero!
foo_use_count: 1;	bar_use_count: 1
foo_str: I'm hero!;  bar_str: Hello World!
foo_str: Hello World!;  bar_str: Hello World!
foo_use_count: 2;	bar_use_count: 2

好了,以上就是shared_ptr这个指针在boost库里面的简单实现,当然还有很多成员函数没有编写出了,若敢兴趣可以下载boost库源码剖析之。明白shared_ptr类是基础,shared_count类是计数类,其通过类sp_counted_base管理真正的指针使用计数,其内部定义有管理use_count_变量的函数。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值