shared_ptr源码分析后续
来源:互联网 发布:网络尺子 在线测量 编辑:程序博客网 时间:2024/04/29 13:25
上次剖析了shared_ptr类的源码,本来肯定也是要说shared_count的,不过由于篇幅,shared_count在这篇博客分析。
shared_ptr类自身有两个成员,一个就是T类型指针,另一个就是shared_count对象了。shared_ptr把所有的计数任务都交给了该成员,最终指针的销毁也是由该对象去执行的(底层实际还有sp_counted_base)。这是一种解耦的思想。
源码分析:
class weak_count;class shared_count{private: sp_counted_base * pi_; friend class weak_count;public: shared_count(): pi_(0) // nothrow { } template<class Y> explicit shared_count( Y * p ): pi_( 0 ) { pi_ = new sp_counted_impl_p<Y>( p ); //new一个impl派生类 if( pi_ == 0 ) //如果失败,就摧毁,这是在定义了BOOST_NO_EXCEPTION情况下,new失败返回值为0。宏定义被我略去。 { boost::checked_delete( p ); boost::throw_exception( std::bad_alloc() ); } } //删除器版本 template<class P, class D> shared_count( P p, D d ): pi_(0) { pi_ = new sp_counted_impl_pd<P, D>(p, d); if(pi_ == 0) { d(p); // delete p boost::throw_exception(std::bad_alloc()); } } //分配器版本 template<class P, class D, class A> shared_count( P p, D d, A a ): pi_( 0 ) { typedef sp_counted_impl_pda<P, D, A> impl_type; typedef typename A::template rebind< impl_type >::other A2; A2 a2( a ); pi_ = a2.allocate( 1, static_cast< impl_type* >( 0 ) ); if( pi_ != 0 ) { new( static_cast< void* >( pi_ ) ) impl_type( p, d, a ); } else { d( p ); //失败要执行d(),销毁操作。 boost::throw_exception( std::bad_alloc() ); } }#ifndef BOOST_NO_AUTO_PTR // auto_ptr<Y> is special cased to provide the strong guarantee //auto_ptr版本,不过C++11已经弃用auto_ptr了 template<class Y> explicit shared_count( std::auto_ptr<Y> & r ): pi_( new sp_counted_impl_p<Y>( r.get() ) ) { r.release(); //在这里release的,呵呵 }#endif #if !defined( BOOST_NO_CXX11_SMART_PTR ) //C++11的unique_ptr版本。 template<class Y, class D> explicit shared_count( std::unique_ptr<Y, D> & r ): pi_( 0 ) { typedef typename sp_convert_reference<D>::type D2; D2 d2( r.get_deleter() ); pi_ = new sp_counted_impl_pd< typename std::unique_ptr<Y, D>::pointer, D2 >( r.get(), d2 ); r.release(); }#endif ~shared_count() // nothrow { if( pi_ != 0 ) pi_->release(); } shared_count(shared_count const & r): pi_(r.pi_) // nothrow { if( pi_ != 0 ) pi_->add_ref_copy(); } explicit shared_count(weak_count const & r); // throws bad_weak_ptr when r.use_count() == 0 shared_count( weak_count const & r, sp_nothrow_tag ); // constructs an empty *this when r.use_count() == 0 //赋值操作 shared_count & operator= (shared_count const & r) // nothrow { sp_counted_base * tmp = r.pi_; if( tmp != pi_ ) { if( tmp != 0 ) tmp->add_ref_copy(); if( pi_ != 0 ) pi_->release(); pi_ = tmp; } return *this; } void swap(shared_count & r) // nothrow { sp_counted_base * tmp = r.pi_; r.pi_ = pi_; pi_ = tmp; } long use_count() const // nothrow { return pi_ != 0? pi_->use_count(): 0; } bool unique() const // nothrow { return use_count() == 1; } bool empty() const // nothrow { return pi_ == 0; } friend inline bool operator==(shared_count const & a, shared_count const & b) { return a.pi_ == b.pi_; } friend inline bool operator<(shared_count const & a, shared_count const & b) { return std::less<sp_counted_base *>()( a.pi_, b.pi_ ); } void * get_deleter( sp_typeinfo const & ti ) const { return pi_? pi_->get_deleter( ti ): 0; } void * get_untyped_deleter() const { return pi_? pi_->get_untyped_deleter(): 0; }};class weak_count{private: sp_counted_base * pi_; friend class shared_count;public: weak_count(): pi_(0) // nothrow { } weak_count(shared_count const & r): pi_(r.pi_) // nothrow { if(pi_ != 0) pi_->weak_add_ref(); } weak_count(weak_count const & r): pi_(r.pi_) // nothrow { if(pi_ != 0) pi_->weak_add_ref(); }// Move support#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) weak_count(weak_count && r): pi_(r.pi_) // nothrow { r.pi_ = 0; }#endif ~weak_count() // nothrow { if(pi_ != 0) pi_->weak_release(); //weak_count析构一次,就减少一次sp_count_base的计数!!!!!! } weak_count & operator= (shared_count const & r) // nothrow { sp_counted_base * tmp = r.pi_; if( tmp != pi_ ) { if(tmp != 0) tmp->weak_add_ref(); if(pi_ != 0) pi_->weak_release(); pi_ = tmp; } return *this; } weak_count & operator= (weak_count const & r) // nothrow { sp_counted_base * tmp = r.pi_; if( tmp != pi_ ) { if(tmp != 0) tmp->weak_add_ref(); if(pi_ != 0) pi_->weak_release(); pi_ = tmp; } return *this; } void swap(weak_count & r) // nothrow { sp_counted_base * tmp = r.pi_; r.pi_ = pi_; pi_ = tmp; } long use_count() const // nothrow { return pi_ != 0? pi_->use_count(): 0; } bool empty() const // nothrow { return pi_ == 0; } friend inline bool operator==(weak_count const & a, weak_count const & b) { return a.pi_ == b.pi_; } friend inline bool operator<(weak_count const & a, weak_count const & b) { return std::less<sp_counted_base *>()(a.pi_, b.pi_); }};//在这里初始化shared_count中的那两个函数,即利用wakt_count的sp_count_base初始化share_count的sp_count_base,它们是共享的//这是在调用weak_ptr的lock函数用weak_ptr构造shared_ptr,然后调用本函数的inline shared_count::shared_count( weak_count const & r ): pi_( r.pi_ ){ if( pi_ == 0 || !pi_->add_ref_lock() ) { boost::throw_exception( boost::bad_weak_ptr() ); }}inline shared_count::shared_count( weak_count const & r, sp_nothrow_tag ): pi_( r.pi_ ){ if( pi_ != 0 && !pi_->add_ref_lock() ) { pi_ = 0; }}
由于shared_count和weak_count在一个头文件中,就一并拿过来了。
shared_count和weak_count如果拥有同一份指针对象,仅有shared_count会增加shared_ptr的引用计数,而weak_count不会。weak_count只是一个观察者。
sp_counted_base
shared_count和weak_count共同维护一个sp_counted_base类对象,当shared_count引用计数为0时,shared_ptr会销毁,但是sp_counted_base不一定销毁,因为它还取决于weak_count,这是weak_ptr自身的引用计数,和shared_ptr无关,当这个引用计数为0时,sp_counted_base自然会调用delete this了。
sp_counted_base类负责了shared_ptr的所有引用计数的计数工作。它是一个基类,它的派生类可以定制不同的删除操作,这对删除器的实现大有帮助。实际上主流平台目前采用原子操作,下面是gcc的版本。
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 ) { } virtual ~sp_counted_base() // nothrow { } // dispose() is called when use_count_ drops to zero, to release // the resources managed by *this. virtual void dispose() = 0; // nothrow // destroy() is called when weak_count_ drops to zero. virtual void destroy() // nothrow { delete this; } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() { atomic_increment( &use_count_ ); } bool add_ref_lock() // true on success { return atomic_conditional_increment( &use_count_ ) != 0; } void release() // nothrow { if( atomic_exchange_and_add( &use_count_, -1 ) == 1 ) { dispose(); weak_release(); //也要执行weak_release,不过由于weak_count不一定为0,所以本release函数没有调用destroy } } //卧槽weak_ptr的weak_count虽然不影响shared_ptr的计数,但是weak_ptr自身也是引用计数只能指针,自身拷贝会增加weak_count void weak_add_ref() // nothrow { atomic_increment( &weak_count_ ); } void weak_release() // nothrow //本函数是release函数中调用的,但只有use_count和weak_count都为0,才销毁sp_counted_bases { if( atomic_exchange_and_add( &weak_count_, -1 ) == 1 ) { destroy(); } } long use_count() const // nothrow { return static_cast<int const volatile &>( use_count_ ); }};
那我们来看一下它的派生类,看一下派生类如何实现dispose操作的:
template<class X> class sp_counted_impl_p: public sp_counted_base{private: X * px_; sp_counted_impl_p( sp_counted_impl_p const & ); sp_counted_impl_p & operator= ( sp_counted_impl_p const & ); typedef sp_counted_impl_p<X> this_type;public: explicit sp_counted_impl_p( X * px ): px_( px ) {#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) boost::sp_scalar_constructor_hook( px, sizeof(X), this );#endif } virtual void dispose() // nothrow {#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) boost::sp_scalar_destructor_hook( px_, sizeof(X), this );#endif boost::checked_delete( px_ ); //check_delete底层检查指针是否为complete类型,是就直接delete px,之前说过,不再赘述 } virtual void * get_deleter( detail::sp_typeinfo const & ) //没有删除器,但是要返回空 { return 0; } virtual void * get_untyped_deleter() { return 0; }#if defined(BOOST_SP_USE_STD_ALLOCATOR) void * operator new( std::size_t ) { return std::allocator<this_type>().allocate( 1, static_cast<this_type *>(0) ); } void operator delete( void * p ) { std::allocator<this_type>().deallocate( static_cast<this_type *>(p), 1 ); }#endif#if defined(BOOST_SP_USE_QUICK_ALLOCATOR) void * operator new( std::size_t ) { return quick_allocator<this_type>::alloc(); } void operator delete( void * p ) { quick_allocator<this_type>::dealloc( p ); }#endif};//删除器版本template<class P, class D> class sp_counted_impl_pd: public sp_counted_base{private: P ptr; // copy constructor must not throw D del; // copy constructor must not throw ...public: // pre: d(p) must not throw sp_counted_impl_pd( P p, D & d ): ptr( p ), del( d ) { } sp_counted_impl_pd( P p ): ptr( p ), del() { } virtual void dispose() // nothrow //这就是使用自定义的删除器,这是和普通指针不同的地方 { del( ptr ); } virtual void * get_deleter( detail::sp_typeinfo const & ti ) //返回删除器指针 { return ti == BOOST_SP_TYPEID(D)? &reinterpret_cast<char&>( del ): 0; } virtual void * get_untyped_deleter() { return &reinterpret_cast<char&>( del ); }#if defined(BOOST_SP_USE_STD_ALLOCATOR) void * operator new( std::size_t ) { return std::allocator<this_type>().allocate( 1, static_cast<this_type *>(0) ); } void operator delete( void * p ) { std::allocator<this_type>().deallocate( static_cast<this_type *>(p), 1 ); }#endif};
还有个定值Allocaor的派生类,就不再分析了。上面两个派生类最重要的的区别就是删除方法不同,一个直接delete,而另一个使用删除器,可能是回调函数。这就是另一种层面的多态。
总结:shared_ptr把所有的计数工作都交给了shared_count类,该类持有一个sp_counted_base类型的指针,sp_counted_base类有两个基类,使用不同的删除方法。shared_count类在构造函数中会new不同的基类初始化sp_counted_base类指针以实现多态。当sp_couted_base类管理的shared_ptr指针引用计数值为0时,会进行shared_ptr保存指针的删除操作。但是sp_counted_base类是否要执行delete this还要看weak_ptr,因为weak_ptr的weak_count类中也持有该指针。如果weak_ptr的自身的引用值为0,那么sp_counted_base类执行delete this,带着派生类一起销毁。
- shared_ptr源码分析后续
- shared_ptr源码分析
- C++ 智能指针(shared_ptr/weak_ptr)源码分析
- shared_ptr源码解读
- shared_ptr源码解读
- shared_ptr源码解读
- shared_ptr源码解读
- shared_ptr源码解读
- shared_ptr源码解读
- shared_ptr源码解读
- boost shared_ptr 源码解析
- C++ shared_ptr源码剖析
- shared_ptr,weak_ptr源码解析
- shared_ptr线程安全性分析
- boost shared_ptr计数分析
- shared_ptr线程安全性分析
- shared_ptr线程安全性分析
- shared_ptr线程安全性分析
- 14 共享内存4
- 第七届蓝桥杯大赛个人赛省赛(软件类)真题 C语言B组 1
- PrefixSpan算法原理总结
- IO流_文件过滤器改进输出指定目录下指定后缀名的文件名称案例、带文件名称过滤器的list()方法的源码
- python kivy windows 安装记录
- shared_ptr源码分析后续
- controller 之间的跳转
- 打印所有的Binary Number
- targan算法
- 数据挖掘随记
- 《深入理解java虚拟机》-虚拟机类加载机制
- LeetCode——5. Longest Palindromic Substring
- 设计模式—关系在代码中实现
- VS2013下socket新函数代替旧函数引起的编译错误