shared_ptr源码分析
2017-01-21 20:36
501 查看
shared_ptr与scoped_ptr一样包装了new操作符在堆上分配的动态对象,但它实现的是引用技术型的智能指针,可以自由地被拷贝和赋值,在任意的地方共享它,当没有代码使用(引用计数为0时)它才删除包装的动态分配的对象。shared_ptr也可以安全地放到标准容器中,弥补了auto_ptr因为转移语义而不能把指针作为STL容器的缺陷。
上面就是shared_ptr的大致源码,我把一些过多的预处理宏,都去掉了。还有过多的C++11的东西,不过仍然保留了部分如移动构造,以及unique_ptr。
shared_ptr可以由一个普通指针构造,它也可以在类内部使用shared_from_this构造(与构造函数那一句有关,稍后分析),甚至auto_ptr或是unique_ptr也都可以。
下面来看shared_ptr的构造函数中奇怪的那一句:
上面这一大堆起了什么作用呢?答案就是初始化enable_shared_from_this相关的引用计数。有了这个我们就可以这样用了:
好了,构造函数就分析到这里,至于sp_deleter_construct()函数,和这个流程一致,只不过加了个删除器而已。
例如:
shared_ptr有多种形式构造函数,应用于各种可能的情形:
无参的shared_ptr()创建一个持有空指针的shared_ptr;
shared_ptr(Y* p)获得指向类型T的指针p的管理权,同时引用计数置为1.这个构造函数要求Y类型必须能够转换为T类型;
shared_ptr(shared_ptr const & r)从另外一个shared_ptr获得指针的管理权,同时引用计数加1,结果是两个shared_ptr共享一个指针的管理权;
shared_ptr(std::auto_ptr< Y> &r)从另外一个auto_ptr获得指针的管理权,引用计数置为1,同时auto_ptr自动失去管理权;
operator=赋值操作符可以从另外一个shared_ptr或auto_ptr获得指针的管理权,其行为同构造函数。
shared_ptr(Y *p, D d)行为类似shared_ptr(Y *p),但是用参数d指定了析构时定值删除器,而不是简单的delete。
shared_ptr的reset()函数与scoped_ptr也不尽相同。它的作用是将引用计数减1,停止对指针的共享,除非引用计数为0,否则不会发生删除操作。带参数的reset()则是类似相同形式的构造函数,原指针引用计数减1的同时改为管理另一个指针。
shared_ptr有两个专门的函数检查引用计数。unique()检查shared_ptr是指针唯一所有者返回true,use_count()返回当前引用计数。use_count()应该仅用于测试或调试,它不提供高效的操作,而且有可能是不可用的(极少数情形)。
shared_ptr还支持比较运算,可以测试两个shared_ptr的相等或不相等,比较基于内部保存的指针,相当于a.get()==b.get()。shared_ptr还可以使用operator<比较大小。同样基于内部保存的指针,但不提供除operator<之外的比较操作符,这使得shared_ptr可以被用于标准关联容器(set和map)。
**shared_ptr的类型转换不能使用static_cast之流,只能使用shared_ptr自己提供的转型函数:static_pointer_cast()、const_pointer_cast()、dynamic_pointer_cast()和reinterpret_cast()函数,它们转型后棵正确返回shared_ptr类型。
此外,shared_ptr还支持流输出操作符operator<<,输出内部指针值,方便调试。
相关代码如下:
上面出现了两种特殊用法:
定值删除器,如上close_socket函数
使用shared_ptr,在作用域结束时可调用任何函数 :)
本次简单剖析了shared_ptr的类源码,至于shared_count等限于篇幅放在后续博客。
参考:
《Boost程序库完全开发指南》,作者:罗剑锋
Boost shared_from_this用法
http://bbs.csdn.net/topics/390872556
源码分析
首先看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; //构造一个空shared_ptr shared_ptr() BOOST_NOEXCEPT : px( 0 ), pn() // never throws in 1.30+ { } //使用指针构造shared_ptr,该Y类型指针必须可以转换为T类型,Y类型可以和T类型一致 template<class Y> //参数不同意味着支持转换,Y类型需要能转换为T类型,比如base-derived explicit shared_ptr( Y * p ): px( p ), pn() // Y must be complete { boost::detail::sp_pointer_construct( this, p, pn ); //为enable_shared_from_this类weak_this_成员初始化,下面会详述。 /* 下面是它底层底层调用的函数,我直接注释在此处 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_enable_shared_from_this( ppx, p, p ); } */ } // // Requirements: D's copy constructor must not throw // // shared_ptr will release p by calling d(p) // //指针、删除器 template<class Y, class D> shared_ptr( Y * p, D d ): px( p ), pn( p, d ) { boost::detail::sp_deleter_construct( this, p ); /*同上,注释 template< class T, class Y > inline void sp_deleter_construct( boost::shared_ptr< T > * ppx, Y * p ) { boost::detail::sp_enable_shared_from_this( ppx, p, p ); } */ } // As above, but with allocator. A's copy constructor shall not throw. //指针、删除器、分配器 template<class Y, class D, class A> shared_ptr( Y * p, D d, A a ): px( p ), pn( p, d, a ) { boost::detail::sp_deleter_construct( this, p ); } // generated copy constructor, destructor are fine... #if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) // ... except in C++0x, move disables the implicit copy //除了在C++ 0x中,移动构造会遮蔽隐式拷贝构造 shared_ptr( shared_ptr const & r ) BOOST_NOEXCEPT : px( r.px ), pn( r.pn ) { } #endif template<class Y> explicit shared_ptr( weak_ptr<Y> const & r ): pn( r.pn ) // may throw { boost::detail::sp_assert_convertible< Y, T >(); //检测Y和T类型是否可以转换 // it is now safe to copy r.px, as pn(r.pn) did not throw px = r.px; } template<class Y> shared_ptr( weak_ptr<Y> const & r, boost::detail::sp_nothrow_tag ) //不抛出异常的版本 BOOST_NOEXCEPT : px( 0 ), pn( r.pn, boost::detail::sp_nothrow_tag() ) { if( !pn.empty() ) { px = r.px; } } template<class Y> shared_ptr( shared_ptr<Y> const & r ) //使用shared_ptr构造 BOOST_NOEXCEPT : px( r.px ), pn( r.pn ) { boost::detail::sp_assert_convertible< Y, T >(); } //意思就是用p构造本shared_ptr,但是本shared_ptr和r共享引用计数,即便本shared_ptr调用reset,只要r不死,那本shared_ptr也不死。共享引用计数两方都可以加减引用计数。 // aliasing template< class Y > shared_ptr( shared_ptr<Y> const & r, element_type * p ) BOOST_NOEXCEPT : px( p ), pn( r.pn ) { } #ifndef BOOST_NO_AUTO_PTR //FIXME //注意这里用的auto_ptr的引用,并且没有调用auto_ptr的release函数,shared_count(r)中会调用 //shared_ptr从一个auto_ptr获得指针的管理权,引用计数置位1,同时auto_ptr将自动失去管理权 template<class Y> explicit shared_ptr( std::auto_ptr<Y> & r ): px(r.get()), pn() { boost::detail::sp_assert_convertible< Y, T >(); Y * tmp = r.get(); pn = boost::detail::shared_count( r ); boost::detail::sp_deleter_construct( this, tmp ); } #if !defined( BOOST_NO_CXX11_SMART_PTR ) && !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) template< class Y, class D > shared_ptr( std::unique_ptr< Y, D > && r ): px( r.get() ), pn() { boost::detail::sp_assert_convertible< Y, T >(); typename std::unique_ptr< Y, D >::pointer tmp = r.get(); pn = boost::detail::shared_count( r ); boost::detail::sp_deleter_construct( this, tmp ); } #endif // assignment shared_ptr & operator=( shared_ptr const & r ) BOOST_NOEXCEPT { this_type(r).swap(*this); return *this; } #ifndef BOOST_NO_AUTO_PTR template<class Y> shared_ptr & operator=( std::auto_ptr<Y> & r ) { this_type( r ).swap( *this ); return *this; } #if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) template<class Y> shared_ptr & operator=( std::auto_ptr<Y> && r ) { this_type( static_cast< std::auto_ptr<Y> && >( r ) ).swap( *this ); return *this; } #endif // BOOST_NO_AUTO_PTR #if !defined( BOOST_NO_CXX11_SMART_PTR ) && !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) //支持C++11的unique_ptr template<class Y, class D> shared_ptr & operator=( std::unique_ptr<Y, D> && r ) { this_type( static_cast< std::unique_ptr<Y, D> && >( r ) ).swap(*this); return *this; } #endif // Move support shared_ptr( shared_ptr && r ) BOOST_NOEXCEPT : px( r.px ), pn() { pn.swap( r.pn ); r.px = 0; } template<class Y> shared_ptr( shared_ptr<Y> && r ) //C++11的移动构造 BOOST_NOEXCEPT : px( r.px ), pn() { boost::detail::sp_assert_convertible< Y, T >(); pn.swap( r.pn ); r.px = 0; } shared_ptr & operator=( shared_ptr && r ) BOOST_NOEXCEPT { this_type( static_cast< shared_ptr && >( r ) ).swap( *this ); return *this; } //仅重置 void reset() BOOST_NOEXCEPT // never throws in 1.30+ { this_type().swap(*this); //666,直接构造一个null对象和this交换 } //重置为p template<class Y> void reset( Y * p ) // Y must be complete { BOOST_ASSERT( p == 0 || p != px ); // catch self-reset errors this_type( p ).swap( *this ); } //这里省略reset的另外两个版本:(1)重置为p指针,带有一个删除器。(2)重置为p指针,带有删除器和内存分配器。 //共享引用计数的模式 template<class Y> void reset( shared_ptr<Y> const & r, element_type * p ) { this_type( r, p ).swap( *this ); } // never throws (but has a BOOST_ASSERT in it, so not marked with BOOST_NOEXCEPT) typename boost::detail::sp_dereference< T >::type operator* () const { BOOST_ASSERT( px != 0 ); return *px; } // never throws (but has a BOOST_ASSERT in it, so not marked with BOOST_NOEXCEPT) typename boost::detail::sp_member_access< T >::type operator-> () const { BOOST_ASSERT( px != 0 ); return px; } // never throws (but has a BOOST_ASSERT in it, so not marked with BOOST_NOEXCEPT) typename boost::detail::sp_array_access< T >::type operator[] ( std::ptrdiff_t i ) const { BOOST_ASSERT( px != 0 ); BOOST_ASSERT( i >= 0 && ( i < boost::detail::sp_extent< T >::value || boost::detail::sp_extent< T >::value == 0 ) ); return px[ i ]; } element_type * get() const BOOST_NOEXCEPT { return px; } // implicit conversion to "bool" #include <boost/smart_ptr/detail/operator_bool.hpp> //重载operator bool //返回引用计数是否为1 bool unique() const BOOST_NOEXCEPT { return pn.unique(); } //返回引用计数 long use_count() const BOOST_NOEXCEPT { return pn.use_count(); } //异常安全的swap,可配合no-member swap函数 void swap( shared_ptr & other ) BOOST_NOEXCEPT { std::swap(px, other.px); pn.swap(other.pn); } //可以理解为是不是要早死吗? template<class Y> bool owner_before( shared_ptr<Y> const & rhs ) const BOOST_NOEXCEPT { return pn < rhs.pn; } template<class Y> bool owner_before( weak_ptr<Y> const & rhs ) const BOOST_NOEXCEPT { return pn < rhs.pn; } //用于内部获取删除器,如果没有返回空,即非删除器构造 void * _internal_get_deleter( boost::detail::sp_typeinfo const & ti ) const BOOST_NOEXCEPT { return pn.get_deleter( ti ); } void * _internal_get_untyped_deleter() const BOOST_NOEXCEPT { return pn.get_untyped_deleter(); } //成员函数比较是否相等,shared_ptr也提供非成员函数比较的方式 bool _internal_equiv( shared_ptr const & r ) const BOOST_NOEXCEPT { return px == r.px && pn == r.pn; } // Tasteless as this may seem, making all members public allows member templates // to work in the absence of member template friends. (Matthew Langston) private: template<class Y> friend class shared_ptr; template<class Y> friend class weak_ptr; element_type * px; // contained pointer boost::detail::shared_count pn; // reference counter }; // shared_ptr
上面就是shared_ptr的大致源码,我把一些过多的预处理宏,都去掉了。还有过多的C++11的东西,不过仍然保留了部分如移动构造,以及unique_ptr。
shared_ptr可以由一个普通指针构造,它也可以在类内部使用shared_from_this构造(与构造函数那一句有关,稍后分析),甚至auto_ptr或是unique_ptr也都可以。
下面来看shared_ptr的构造函数中奇怪的那一句:
template<class Y> explicit shared_ptr( Y * p ): px( p ), pn() // px是被管理的对象指针;pn是引用计数器,shared_ptr内部管理 { 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 ) { //至于为什么用swap来构造pn,我认为这是为了异常安全,因为pn构造函数中用到了new boost::detail::shared_count( p ).swap( pn ); // 创建引用计数器,swap等价于赋值给pn boost::detail::sp_enable_shared_from_this( ppx, p, p ); } // sp_enable_shared_from_this 模板重载了多个,针对被管理的是enable_shared_from_this的派生类的对象时自动选择执行这个函数 template< class X, class Y, class T > inline void sp_enable_shared_from_this( boost::shared_ptr<X> const * ppx, Y const * py, boost::enable_shared_from_this< T > const * pe ) //注第三个参数类型是enable_shared_from_this,使用基类指针指向派生类 { if( pe != 0 ) { pe->_internal_accept_owner( ppx, const_cast< Y* >( py ) ); } } template<class T> class enable_shared_from_this { public: // 获取指向自身的智能指针,weak_ptr作为观察者能够判断指针是否已经释放 shared_ptr<T> shared_from_this() { shared_ptr<T> p( weak_this_ ); BOOST_ASSERT( p.get() == this ); // 如果指针已经释放,那么这里就会报错了 return p; } shared_ptr<T const> shared_from_this() const { shared_ptr<T const> p( weak_this_ ); BOOST_ASSERT( p.get() == this ); return p; } public: // 派生对象内部保存一份私有的weak_ptr,用来获取指向自身(this)的智能指针 // Note: invoked automatically by shared_ptr; do not call template<class X, class Y> void _internal_accept_owner( shared_ptr<X> const * ppx, Y * py ) const { if( weak_this_.expired() ) { weak_this_ = shared_ptr<T>( *ppx, py ); //这里就构造了一个weak_ptr,且其目前监视的对象引用计数为1, //调用shread_ptr的shared_ptr( shared_ptr<Y> const & r, element_type * p ),使用p构造一个shared_ptr和r共享引用计数,而r正是我们最初要构造的shared_ptr的this指针,p即我们最初传给shared_ptr的参数 //所以这里相当于赋值该weak_ptr,以后该weak_ptr就监视本shared_ptr了 //为什么说赋值,因为weak_count已经默认初始化过了,只不过weak_count之前为0,详见enable_shared_from_this类构造函数 } } private: mutable weak_ptr<T> weak_this_; };
上面这一大堆起了什么作用呢?答案就是初始化enable_shared_from_this相关的引用计数。有了这个我们就可以这样用了:
class Y: public boost::enable_shared_from_this<Y> { public: boost::shared_ptr<Y> f() { return shared_from_this(); } }; // 正确的使用方法 boost::shared_ptr<Y> p(new Y); boost::shared_ptr<Y> q = p->f(); // 错误的使用方法,因为Y的成员weak_ptr 根本就没有得到初始化,必须先使用shared_ptr管理class才可以 Y yy; boost::shared_ptr<Y> q = yy.f();
好了,构造函数就分析到这里,至于sp_deleter_construct()函数,和这个流程一致,只不过加了个删除器而已。
操作函数
shared_ptr与scoped_ptr同样是用于管理new动态分配对象的智能指针,因此功能上有很多相似之处:它们都重载了*和->操作符以模仿原始指针的行为,提供隐式bool类型转换以判断指针的有效性,get可以得到原始指针(return px),并且没有提供指针算数操作。例如:
shared_ptr<int> spi(new int); assert(spi); *spi = 253; shared_ptr<string> sps(new string("smart")); assert(sps->size() == 5);
shared_ptr有多种形式构造函数,应用于各种可能的情形:
无参的shared_ptr()创建一个持有空指针的shared_ptr;
shared_ptr(Y* p)获得指向类型T的指针p的管理权,同时引用计数置为1.这个构造函数要求Y类型必须能够转换为T类型;
shared_ptr(shared_ptr const & r)从另外一个shared_ptr获得指针的管理权,同时引用计数加1,结果是两个shared_ptr共享一个指针的管理权;
shared_ptr(std::auto_ptr< Y> &r)从另外一个auto_ptr获得指针的管理权,引用计数置为1,同时auto_ptr自动失去管理权;
operator=赋值操作符可以从另外一个shared_ptr或auto_ptr获得指针的管理权,其行为同构造函数。
shared_ptr(Y *p, D d)行为类似shared_ptr(Y *p),但是用参数d指定了析构时定值删除器,而不是简单的delete。
shared_ptr的reset()函数与scoped_ptr也不尽相同。它的作用是将引用计数减1,停止对指针的共享,除非引用计数为0,否则不会发生删除操作。带参数的reset()则是类似相同形式的构造函数,原指针引用计数减1的同时改为管理另一个指针。
shared_ptr有两个专门的函数检查引用计数。unique()检查shared_ptr是指针唯一所有者返回true,use_count()返回当前引用计数。use_count()应该仅用于测试或调试,它不提供高效的操作,而且有可能是不可用的(极少数情形)。
shared_ptr还支持比较运算,可以测试两个shared_ptr的相等或不相等,比较基于内部保存的指针,相当于a.get()==b.get()。shared_ptr还可以使用operator<比较大小。同样基于内部保存的指针,但不提供除operator<之外的比较操作符,这使得shared_ptr可以被用于标准关联容器(set和map)。
**shared_ptr的类型转换不能使用static_cast之流,只能使用shared_ptr自己提供的转型函数:static_pointer_cast()、const_pointer_cast()、dynamic_pointer_cast()和reinterpret_cast()函数,它们转型后棵正确返回shared_ptr类型。
此外,shared_ptr还支持流输出操作符operator<<,输出内部指针值,方便调试。
相关代码如下:
template<class T, class U> inline bool operator<(shared_ptr<T> const & a, shared_ptr<U> const & b) BOOST_NOEXCEPT { return a.owner_before( b ); } template<class T> inline void swap(shared_ptr<T> & a, shared_ptr<T> & b) BOOST_NOEXCEPT { a.swap(b); } template<class T, class U> shared_ptr<T> static_pointer_cast( shared_ptr<U> const & r ) BOOST_NOEXCEPT { (void) static_cast< T* >( static_cast< U* >( 0 ) ); typedef typename shared_ptr<T>::element_type E; E * p = static_cast< E* >( r.get() ); return shared_ptr<T>( r, p ); } template<class T, class U> shared_ptr<T> const_pointer_cast( shared_ptr<U> const & r ) BOOST_NOEXCEPT { (void) const_cast< T* >( static_cast< U* >( 0 ) ); typedef typename shared_ptr<T>::element_type E; E * p = const_cast< E* >( r.get() ); return shared_ptr<T>( r, p ); } template<class T, class U> shared_ptr<T> dynamic_pointer_cast( shared_ptr<U> const & r ) BOOST_NOEXCEPT { (void) dynamic_cast< T* >( static_cast< U* >( 0 ) ); typedef typename shared_ptr<T>::element_type E; E * p = dynamic_cast< E* >( r.get() ); return p? shared_ptr<T>( r, p ): shared_ptr<T>(); } template<class T, class U> shared_ptr<T> reinterpret_pointer_cast( shared_ptr<U> const & r ) BOOST_NOEXCEPT { (void) reinterpret_cast< T* >( static_cast< U* >( 0 ) ); typedef typename shared_ptr<T>::element_type E; E * p = reinterpret_cast< E* >( r.get() ); return shared_ptr<T>( r, p ); }
用法
这里只给出一些特殊用法:class socket_t {}; socket_t* open_socket() { cout<<"open socket"<<endl; return new socket_t; } void close_socket(socket_t *s) { cout<<"close_socket"<<endl; } void anyfunc(void *) { cout<<"hehe"<<endl; } int main() { socket_t *s = open_socket(); shared_ptr<socket_t> p(s, close_socket); // shared_ptr<FILE> fp(fopen("./1.txt","r"), fclose); shared_ptr<void> v((void*)0, anyfunc); return 0; }
上面出现了两种特殊用法:
定值删除器,如上close_socket函数
使用shared_ptr,在作用域结束时可调用任何函数 :)
本次简单剖析了shared_ptr的类源码,至于shared_count等限于篇幅放在后续博客。
参考:
《Boost程序库完全开发指南》,作者:罗剑锋
Boost shared_from_this用法
http://bbs.csdn.net/topics/390872556
相关文章推荐
- 详解 boost 库智能指针(scoped_ptr<T> 、shared_ptr<T> 、weak_ptr<T> 源码分析)
- [置顶] 从零开始学C++之boost库(一):详解 boost 库智能指针(scoped_ptr<T> 、shared_ptr<T> 、weak_ptr<T> 源码分析)
- C++ 智能指针(shared_ptr/weak_ptr)源码分析
- shared_ptr源码分析后续
- 从零开始学C++之boost库(一):详解 boost 库智能指针(scoped_ptr<T> 、shared_ptr<T> 、weak_ptr<T> 源码分析)
- [置顶] 从零开始学C++之boost库(一):详解 boost 库智能指针(scoped_ptr<T> 、shared_ptr<T> 、weak_ptr<T> 源码分析)
- 详解 boost 库智能指针(scoped_ptr<T> 、shared_ptr<T> 、weak_ptr<T> 源码分析)
- std::tr1::shared_ptr源码赏析
- boost源码剖析3----内存管理shared_ptr
- shared_ptr智能指针源码剖析
- shared_ptr源码解读
- shared_ptr线程安全性全面分析
- Boost源码学习---shared_ptr.hpp
- boost::shared_ptr 分析与实现
- [C++] Boost智能指针——boost::shared_ptr(使用及原理分析)
- folly源码分析(3)- ThreadLocalPtr
- shared_ptr源码解读
- 《我的泛型编程观》之boost.scoped_ptr、scoped_array源码分析
- boost::shared_ptr 分析与实现
- shared_ptr源码解读