Chinaunix首页 | 论坛 | 博客
  • 博客访问: 685226
  • 博文数量: 209
  • 博客积分: 26
  • 博客等级: 民兵
  • 技术积分: 326
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-21 09:29
文章分类

全部博文(209)

文章存档

2015年(6)

2014年(40)

2013年(154)

2012年(11)

我的朋友

分类: C/C++

2013-04-07 15:15:29

原文地址:shared_ptr相关源代码分析 作者:qgx2009

shared_ptr是平时用的比较多的智能指针类型,本人基本了解智能指针的原理是通过引用计数来实现的,之前也实现过一个,后来shared_ptr出现后就不再使用其它的了,boost文档中提到shared_ptr是线程安全的,对线程安全比较好奇,所以察看了shared_ptr的源代码。
shared_ptr的源代码略复杂,各种构造函数占用了较大的篇幅,之后是reset,*和-〉的运算符重载等。总的来说思路是常规思路。
shared_ptr有两个成员    

点击(此处)折叠或打开

  1.     T * px; // 指针
  2.     boost::detail::shared_count pn; // 引用计数 -- 后面介绍
看一下swap函数。这个函数在shared_ptr内部使用的较多   

点击(此处)折叠或打开

  1.     void swap(shared_ptr<T> & other) // never throws
  2.     {
  3.         std::swap(px, other.px);
  4.         pn.swap(other.pn);
  5.     }
该函数调用std的swap函数交换 指针,然后调用shared_count::swap替换引用计数。
线程安全分为几个场景:比如多个thread同时读、同时写、同是读写。从这一点看shared_ptr同时读没有问题的,但是同时写或同时读写就会有问题了,所以shared_ptr并不是完全线程安全的。

shared_ptr的核心就是shared_count,因为整个shared_ptr实现都没有出现对引用计数的具体操作,比如+1 -1等。而每一次需要用到对引用计数的操作都调用了shared_count内部封装的函数,比如:swap、==、get_deleter、use_count等。

shared_count 内部包含sp_counted_base *pi_,该成员在shared_count的构造函数里初始化,从名字可以看出sp_counted_base是一个基类。shared_count在构造函数里对*pi_进行初始化。 

点击(此处)折叠或打开

  1.   template<class Y> explicit shared_count( Y * p ): pi_( 0 )
  2.   {
  3.       ……
  4.       pi_ = new sp_counted_impl_p<Y>( p );
  5.       ……
  6.   }

  7.   template<class P, class D> shared_count( P p, D d ): pi_(0)
  8.   {
  9.        ……
  10.        pi_ = new sp_counted_impl_pd<P, D>(p, d);
  11.        ……
  12.   }
sp_counted_base 类主要对引用计数进行管理,它内部包含两个成员:
   

点击(此处)折叠或打开

  1. long use_count_; // #shared
  2. long weak_count_; // #weak + (#shared != 0)
这两个成员是私有的,只能通过成员函数进行修改,比如:

点击(此处)折叠或打开

  1.     void add_ref_copy()
  2.     {
  3.         ++use_count_;
  4.     }
其他的成员函数还有:add_ref_lock() 、 release()等都是对引用计数操作。   

点击(此处)折叠或打开

  1.     void release() // nothrow
  2.     {
  3.         if( --use_count_ == 0 )
  4.         {
  5.             dispose();
  6.             weak_release();
  7.         }
  8.     }

release函数调用了dispose,该函数是纯虚函数,该函数在其他 sp_counted_base 的子类里面实现,weak_release暂时不讨论。  

点击(此处)折叠或打开

  1. virtual void dispose() = 0; // nothrow
我们看一下 sp_counted_impl_pd 的实现,sp_counted_impl_pd 是 sp_counted_base的子类,有两个成员   

点击(此处)折叠或打开

  1. P ptr; // copy constructor must not throw
  2. D del; // copy constructor must not throw
sp_counted_impl_pd内部对new 和 delete进行了重载,并且实现了dispose():  

点击(此处)折叠或打开

  1.     virtual void dispose() // nothrow
  2.     {
  3.         del( ptr );
  4.     }

del应该是一个函数对象,当use_count_为0时调用该函数对象,官方的解释是定制销毁器,就是如果我们的对象不是通过new分配的,所以不能通过delete销毁,那就需要用户指定销毁方式。
阅读(3151) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~