C++11智能指针
今晚跟同学谈了一下智能指针,突然想要看一下C++11的智能指针的实现,因此下了这篇博文。
以下代码出自于VS2012 <memory>
template<class _Ty>
class shared_ptr
: public _Ptr_base<_Ty>
{ // class for reference counted resource management
public:
typedef shared_ptr<_Ty> _Myt;
typedef _Ptr_base<_Ty> _Mybase; shared_ptr() _NOEXCEPT
{ // construct empty shared_ptr object
} template<class _Ux>
explicit shared_ptr(_Ux *_Px)
{ // construct shared_ptr object that owns _Px
_Resetp(_Px);
} template<class _Ux,
class _Dx>
shared_ptr(_Ux *_Px, _Dx _Dt)
{ // construct with _Px, deleter
_Resetp(_Px, _Dt);
} //#if _HAS_CPP0X shared_ptr(nullptr_t)
{ // construct with nullptr
_Resetp((_Ty *));
} template<class _Dx>
shared_ptr(nullptr_t, _Dx _Dt)
{ // construct with nullptr, deleter
_Resetp((_Ty *), _Dt);
} template<class _Dx,
class _Alloc>
shared_ptr(nullptr_t, _Dx _Dt, _Alloc _Ax)
{ // construct with nullptr, deleter, allocator
_Resetp((_Ty *), _Dt, _Ax);
} template<class _Ux,
class _Dx,
class _Alloc>
shared_ptr(_Ux *_Px, _Dx _Dt, _Alloc _Ax)
{ // construct with _Px, deleter, allocator
_Resetp(_Px, _Dt, _Ax);
}
//#endif /* _HAS_CPP0X */ #if _HAS_CPP0X
template<class _Ty2>
shared_ptr(const shared_ptr<_Ty2>& _Right, _Ty *_Px) _NOEXCEPT
{ // construct shared_ptr object that aliases _Right
this->_Reset(_Px, _Right);
}
#endif /* _HAS_CPP0X */ shared_ptr(const _Myt& _Other) _NOEXCEPT
{ // construct shared_ptr object that owns same resource as _Other
this->_Reset(_Other);
} template<class _Ty2>
shared_ptr(const shared_ptr<_Ty2>& _Other,
typename enable_if<is_convertible<_Ty2 *, _Ty *>::value,
void>::type ** = ) _NOEXCEPT
{ // construct shared_ptr object that owns same resource as _Other
this->_Reset(_Other);
} template<class _Ty2>
explicit shared_ptr(const weak_ptr<_Ty2>& _Other,
bool _Throw = true)
{ // construct shared_ptr object that owns resource *_Other
this->_Reset(_Other, _Throw);
} template<class _Ty2>
shared_ptr(auto_ptr<_Ty2>&& _Other)
{ // construct shared_ptr object that owns *_Other.get()
this->_Reset(_STD move(_Other));
} template<class _Ty2>
shared_ptr(const shared_ptr<_Ty2>& _Other, const _Static_tag& _Tag)
{ // construct shared_ptr object for static_pointer_cast
this->_Reset(_Other, _Tag);
} template<class _Ty2>
shared_ptr(const shared_ptr<_Ty2>& _Other, const _Const_tag& _Tag)
{ // construct shared_ptr object for const_pointer_cast
this->_Reset(_Other, _Tag);
} template<class _Ty2>
shared_ptr(const shared_ptr<_Ty2>& _Other, const _Dynamic_tag& _Tag)
{ // construct shared_ptr object for dynamic_pointer_cast
this->_Reset(_Other, _Tag);
} shared_ptr(_Myt&& _Right) _NOEXCEPT
: _Mybase(_STD forward<_Myt>(_Right))
{ // construct shared_ptr object that takes resource from _Right
} template<class _Ty2>
shared_ptr(shared_ptr<_Ty2>&& _Right,
typename enable_if<is_convertible<_Ty2 *, _Ty *>::value,
void>::type ** = ) _NOEXCEPT
: _Mybase(_STD forward<shared_ptr<_Ty2> >(_Right))
{ // construct shared_ptr object that takes resource from _Right
} #if _HAS_CPP0X
template<class _Ux,
class _Dx>
shared_ptr(unique_ptr<_Ux, _Dx>&& _Right)
{ // construct from unique_ptr
_Resetp(_Right.release(), _Right.get_deleter());
} template<class _Ux,
class _Dx>
_Myt& operator=(unique_ptr<_Ux, _Dx>&& _Right)
{ // move from unique_ptr
shared_ptr(_STD move(_Right)).swap(*this);
return (*this);
}
#endif /* _HAS_CPP0X */ _Myt& operator=(_Myt&& _Right) _NOEXCEPT
{ // construct shared_ptr object that takes resource from _Right
shared_ptr(_STD move(_Right)).swap(*this);
return (*this);
} template<class _Ty2>
_Myt& operator=(shared_ptr<_Ty2>&& _Right) _NOEXCEPT
{ // construct shared_ptr object that takes resource from _Right
shared_ptr(_STD move(_Right)).swap(*this);
return (*this);
} ~shared_ptr() _NOEXCEPT
{ // release resource
this->_Decref();
} _Myt& operator=(const _Myt& _Right) _NOEXCEPT
{ // assign shared ownership of resource owned by _Right
shared_ptr(_Right).swap(*this);
return (*this);
} template<class _Ty2>
_Myt& operator=(const shared_ptr<_Ty2>& _Right) _NOEXCEPT
{ // assign shared ownership of resource owned by _Right
shared_ptr(_Right).swap(*this);
return (*this);
} template<class _Ty2>
_Myt& operator=(auto_ptr<_Ty2>&& _Right)
{ // assign ownership of resource pointed to by _Right
shared_ptr(_STD move(_Right)).swap(*this);
return (*this);
} void reset() _NOEXCEPT
{ // release resource and convert to empty shared_ptr object
shared_ptr().swap(*this);
} template<class _Ux>
void reset(_Ux *_Px)
{ // release, take ownership of _Px
shared_ptr(_Px).swap(*this);
} template<class _Ux,
class _Dx>
void reset(_Ux *_Px, _Dx _Dt)
{ // release, take ownership of _Px, with deleter _Dt
shared_ptr(_Px, _Dt).swap(*this);
} //#if _HAS_CPP0X
template<class _Ux,
class _Dx,
class _Alloc>
void reset(_Ux *_Px, _Dx _Dt, _Alloc _Ax)
{ // release, take ownership of _Px, with deleter _Dt, allocator _Ax
shared_ptr(_Px, _Dt, _Ax).swap(*this);
}
//#endif /* _HAS_CPP0X */ void swap(_Myt& _Other) _NOEXCEPT
{ // swap pointers
this->_Swap(_Other);
} _Ty *get() const _NOEXCEPT
{ // return pointer to resource
return (this->_Get());
} typename add_reference<_Ty>::type operator*() const _NOEXCEPT
{ // return reference to resource
return (*this->_Get());
} _Ty *operator->() const _NOEXCEPT
{ // return pointer to resource
return (this->_Get());
} bool unique() const _NOEXCEPT
{ // return true if no other shared_ptr object owns this resource
return (this->use_count() == );
} _TYPEDEF_BOOL_TYPE; _OPERATOR_BOOL() const _NOEXCEPT
{ // test if shared_ptr object owns no resource
return (this->_Get() != ? _CONVERTIBLE_TO_TRUE : );
} private:
template<class _Ux>
void _Resetp(_Ux *_Px)
{ // release, take ownership of _Px
_TRY_BEGIN // allocate control block and reset
_Resetp0(_Px, new _Ref_count<_Ux>(_Px));
_CATCH_ALL // allocation failed, delete resource
delete _Px;
_RERAISE;
_CATCH_END
} template<class _Ux,
class _Dx>
void _Resetp(_Ux *_Px, _Dx _Dt)
{ // release, take ownership of _Px, deleter _Dt
_TRY_BEGIN // allocate control block and reset
_Resetp0(_Px, new _Ref_count_del<_Ux, _Dx>(_Px, _Dt));
_CATCH_ALL // allocation failed, delete resource
_Dt(_Px);
_RERAISE;
_CATCH_END
} //#if _HAS_CPP0X
template<class _Ux,
class _Dx,
class _Alloc>
void _Resetp(_Ux *_Px, _Dx _Dt, _Alloc _Ax)
{ // release, take ownership of _Px, deleter _Dt, allocator _Ax
typedef _Ref_count_del_alloc<_Ux, _Dx, _Alloc> _Refd;
typename _Alloc::template rebind<_Refd>::other _Al = _Ax; _TRY_BEGIN // allocate control block and reset
_Refd *_Ptr = _Al.allocate();
::new (_Ptr) _Refd(_Px, _Dt, _Al);
_Resetp0(_Px, _Ptr);
_CATCH_ALL // allocation failed, delete resource
_Dt(_Px);
_RERAISE;
_CATCH_END
}
//#endif /* _HAS_CPP0X */ public:
template<class _Ux>
void _Resetp0(_Ux *_Px, _Ref_count_base *_Rx)
{ // release resource and take ownership of _Px
this->_Reset0(_Px, _Rx);
_Enable_shared(_Px, _Rx);
}
};
我们可以看到shared_ptr是继承于_Ptr_base的,(同时weak_ptr也继承与_Ptr_base)
那么我们先来看一下_Ptr_base里有什么东西
首先我们可以看到_Ptr_base里面有两个属性
private:
_Ty *_Ptr;
_Ref_count_base *_Rep;
从shared_ptr我们知道_Ptr_base是个模板,而_Ty是传到_Ptr_base里的模板参数,也就是指针的类型
所以我们知道 _Ptr 保存的值就是真正的指针
但是 _Ref_count_base *_Rep 是什么东西呢,很明显就是引用计数。为什么要用指针呢,因为拥有相同_Ptr值的智能指针要拥有同一个引用计数,因此 _Rep 必须为指针。我们把引用计数类_Ref_count_base 放到后面去讨论。
我们继续看一下shared_ptr的源码可以发现shared_ptr没有显式调用_Ptr_base的构造函数,这意味着shared_ptr只调用_Ptr_base的默认构造函数,但是
shared_ptr的构造函数里大量的调用了两个函数 _Resetp 和 _Reset。
------------------------------------------------------------ _Ptr_base的构造函数 -------------------------------------------------------------------
我们先看一下_Ptr_base的构造函数
_Ptr_base()
: _Ptr(), _Rep()
{ // construct
} _Ptr_base(_Myt&& _Right)
: _Ptr(), _Rep()
{ // construct _Ptr_base object that takes resource from _Right
_Assign_rv(_STD forward<_Myt>(_Right));
} template<class _Ty2>
_Ptr_base(_Ptr_base<_Ty2>&& _Right)
: _Ptr(_Right._Ptr), _Rep(_Right._Rep)
{ // construct _Ptr_base object that takes resource from _Right
_Right._Ptr = ;
_Right._Rep = ;
}
_Ptr_base的默认构造函数是指针置位nullptr,这没什么好说的。剩下两个是转移构造函数,比较奇怪的是
template<class _Ty2>
_Ptr_base(_Ptr_base<_Ty2>&& _Right)
接受以任意类型作为模板参数的_Ptr_base?不懂,估计与shared_ptr向上转型有关。
------------------------------------------------------------ _Ptr_base的_Resetp函数 -------------------------------------------------------------
然后我们看一下_Resetp函数
template<class _Ux>
void _Resetp(_Ux *_Px)
{ // release, take ownership of _Px
_TRY_BEGIN // allocate control block and reset
_Resetp0(_Px, new _Ref_count<_Ux>(_Px));
_CATCH_ALL // allocation failed, delete resource
delete _Px;
_RERAISE;
_CATCH_END
} template<class _Ux,
class _Dx>
void _Resetp(_Ux *_Px, _Dx _Dt)
{ // release, take ownership of _Px, deleter _Dt
_TRY_BEGIN // allocate control block and reset
_Resetp0(_Px, new _Ref_count_del<_Ux, _Dx>(_Px, _Dt));
_CATCH_ALL // allocation failed, delete resource
_Dt(_Px);
_RERAISE;
_CATCH_END
} //#if _HAS_CPP0X
template<class _Ux,
class _Dx,
class _Alloc>
void _Resetp(_Ux *_Px, _Dx _Dt, _Alloc _Ax)
{ // release, take ownership of _Px, deleter _Dt, allocator _Ax
typedef _Ref_count_del_alloc<_Ux, _Dx, _Alloc> _Refd;
typename _Alloc::template rebind<_Refd>::other _Al = _Ax; _TRY_BEGIN // allocate control block and reset
_Refd *_Ptr = _Al.allocate();
::new (_Ptr) _Refd(_Px, _Dt, _Al);
_Resetp0(_Px, _Ptr);
_CATCH_ALL // allocation failed, delete resource
_Dt(_Px);
_RERAISE;
_CATCH_END
}
_Resetp函数有三个重载,实际上就是 是否带析构器_Dx 和 是否带构造器_Alloc, 这两个参数都用于引用计数,我们继续留到后面讨论。
_Resetp函数的三个重载里又都调用了_Resetp0
template<class _Ux>
void _Resetp0(_Ux *_Px, _Ref_count_base *_Rx)
{ // release resource and take ownership of _Px
this->_Reset0(_Px, _Rx);
_Enable_shared(_Px, _Rx);
}
这里又调用了父类_Ptr_base的_Reset0 和另一个函数_Enable_shared
先看一下_Reset0
void _Reset0(_Ty *_Other_ptr, _Ref_count_base *_Other_rep)
{ // release resource and take new resource
if (_Rep != )
_Rep->_Decref();
_Rep = _Other_rep;
_Ptr = _Other_ptr;
}
就是检查一下当前_Ptr_base引用计数指针是否为空,非空就释放一个引用计数,然后更新指针值和引用计数值
(为什么叫_Reset0? 0表示最基本的Reset?)
再看一下_Enable_shared
template<class _Ty>
inline void _Enable_shared(_Ty *_Ptr, _Ref_count_base *_Refptr,
typename _Ty::_EStype * = )
{ // reset internal weak pointer
if (_Ptr)
_Do_enable(_Ptr,
(enable_shared_from_this<typename _Ty::_EStype>*)_Ptr, _Refptr);
} inline void _Enable_shared(const volatile void *, const volatile void *)
{ // not derived from enable_shared_from_this; do nothing
}
这里用了模板的最特化匹配
当_Ty有定义_EStype这个类型名的时候(也就是_Ty继承于enable_shared_from_this<_Ty>的时候)会调用第一个函数。
这里我简单描述一下_Do_enable的作用:
因为_Ty继承于enable_shared_from_this<typename _Ty::_EStype>(实际上_Ty::_EStype就是_Ty,有兴趣的朋友可以去看一下 enable_shared_from_this的源码),enable_shared_from_this<typename _Ty::_EStype>内部保存着一个weak_ptr<_Ty>的弱指针,而_Do_enable的作用就是更新一下这个弱指针的值(使用过shared_ptr的朋友都应该知道enable_shared_from_this是用于共享this指针,而这个共享this指针的操作就是通过这个weak_ptr达到的)。
------------------------------------------------------------ shared_ptr的构造函数 -------------------------------------------------------------
接着我们看一下shared_ptr的调用了_reset的构造函数
shared_ptr(const _Myt& _Other) _NOEXCEPT
{ // construct shared_ptr object that owns same resource as _Other
this->_Reset(_Other);
} template<class _Ty2>
shared_ptr(const shared_ptr<_Ty2>& _Other,
typename enable_if<is_convertible<_Ty2 *, _Ty *>::value,
void>::type ** = ) _NOEXCEPT
{ // construct shared_ptr object that owns same resource as _Other
this->_Reset(_Other);
} template<class _Ty2>
explicit shared_ptr(const weak_ptr<_Ty2>& _Other,
bool _Throw = true)
{ // construct shared_ptr object that owns resource *_Other
this->_Reset(_Other, _Throw);
} template<class _Ty2>
shared_ptr(auto_ptr<_Ty2>&& _Other)
{ // construct shared_ptr object that owns *_Other.get()
this->_Reset(_STD move(_Other));
} template<class _Ty2>
shared_ptr(const shared_ptr<_Ty2>& _Other, const _Static_tag& _Tag)
{ // construct shared_ptr object for static_pointer_cast
this->_Reset(_Other, _Tag);
} template<class _Ty2>
shared_ptr(const shared_ptr<_Ty2>& _Other, const _Const_tag& _Tag)
{ // construct shared_ptr object for const_pointer_cast
this->_Reset(_Other, _Tag);
} template<class _Ty2>
shared_ptr(const shared_ptr<_Ty2>& _Other, const _Dynamic_tag& _Tag)
{ // construct shared_ptr object for dynamic_pointer_cast
this->_Reset(_Other, _Tag);
}
这里又用到了模板的最特化匹配,注意L1 - L12
is_convertible<_Ty2 *, _Ty *>::value
是C++11提供的一个类型测试模板,用于测试_Ty2 * 与 _Ty *之间是否有合法转换。当有的时候将调用函数L6 - L12,否则调用L1 - L4
这也是shared_ptr<_Ty>可以向shared_ptr<_Ty的父类>向上转型的秘密。
PS:注意shared_ptr还有一个转移构造函数与上面提到的_Ptr_base的转移构造函数相对应
template<class _Ty2>
shared_ptr(shared_ptr<_Ty2>&& _Right,
typename enable_if<is_convertible<_Ty2 *, _Ty *>::value,
void>::type ** = ) _NOEXCEPT
: _Mybase(_STD forward<shared_ptr<_Ty2> >(_Right))
{ // construct shared_ptr object that takes resource from _Right
}
然后L27 - L43的三个构造函数分别用于static_cast、const_cast、dynamic_cast转型。
转型函数见
template<class _Ty1,
class _Ty2>
shared_ptr<_Ty1>
static_pointer_cast(const shared_ptr<_Ty2>& _Other) _NOEXCEPT
{ // return shared_ptr object holding static_cast<_Ty1 *>(_Other.get())
return (shared_ptr<_Ty1>(_Other, _Static_tag()));
} template<class _Ty1,
class _Ty2>
shared_ptr<_Ty1>
const_pointer_cast(const shared_ptr<_Ty2>& _Other) _NOEXCEPT
{ // return shared_ptr object holding const_cast<_Ty1 *>(_Other.get())
return (shared_ptr<_Ty1>(_Other, _Const_tag()));
} template<class _Ty1,
class _Ty2>
shared_ptr<_Ty1>
dynamic_pointer_cast(const shared_ptr<_Ty2>& _Other) _NOEXCEPT
{ // return shared_ptr object holding dynamic_cast<_Ty1 *>(_Other.get())
return (shared_ptr<_Ty1>(_Other, _Dynamic_tag()));
}
------------------------------------------------------------ _Ptr_base的_Reset函数 -------------------------------------------------------------
我们最后我们看一下_Ptr_base的_Reset函数
void _Reset()
{ // release resource
_Reset(, );
} template<class _Ty2>
void _Reset(const _Ptr_base<_Ty2>& _Other)
{ // release resource and take ownership of _Other._Ptr
_Reset(_Other._Ptr, _Other._Rep);
} template<class _Ty2>
void _Reset(const _Ptr_base<_Ty2>& _Other, bool _Throw)
{ // release resource and take ownership from weak_ptr _Other._Ptr
_Reset(_Other._Ptr, _Other._Rep, _Throw);
} template<class _Ty2>
void _Reset(const _Ptr_base<_Ty2>& _Other, const _Static_tag&)
{ // release resource and take ownership of _Other._Ptr
_Reset(static_cast<_Elem *>(_Other._Ptr), _Other._Rep);
} template<class _Ty2>
void _Reset(const _Ptr_base<_Ty2>& _Other, const _Const_tag&)
{ // release resource and take ownership of _Other._Ptr
_Reset(const_cast<_Elem *>(_Other._Ptr), _Other._Rep);
} template<class _Ty2>
void _Reset(const _Ptr_base<_Ty2>& _Other, const _Dynamic_tag&)
{ // release resource and take ownership of _Other._Ptr
_Elem *_Ptr = dynamic_cast<_Elem *>(_Other._Ptr);
if (_Ptr)
_Reset(_Ptr, _Other._Rep);
else
_Reset();
} template<class _Ty2>
void _Reset(auto_ptr<_Ty2>&& _Other)
{ // release resource and take _Other.get()
_Ty2 *_Px = _Other.get();
_Reset0(_Px, new _Ref_count<_Elem>(_Px));
_Other.release();
_Enable_shared(_Px, _Rep);
} #if _HAS_CPP0X
template<class _Ty2>
void _Reset(_Ty *_Ptr, const _Ptr_base<_Ty2>& _Other)
{ // release resource and alias _Ptr with _Other_rep
_Reset(_Ptr, _Other._Rep);
}
#endif /* _HAS_CPP0X */ void _Reset(_Ty *_Other_ptr, _Ref_count_base *_Other_rep)
{ // release resource and take _Other_ptr through _Other_rep
if (_Other_rep)
_Other_rep->_Incref();
_Reset0(_Other_ptr, _Other_rep);
} void _Reset(_Ty *_Other_ptr, _Ref_count_base *_Other_rep, bool _Throw)
{ // take _Other_ptr through _Other_rep from weak_ptr if not expired
// otherwise, leave in default state if !_Throw,
// otherwise throw exception
if (_Other_rep && _Other_rep->_Incref_nz())
_Reset0(_Other_ptr, _Other_rep);
else if (_Throw)
_THROW_NCEE(bad_weak_ptr, );
}
实际上也就是转发一下到_Reset0函数
------------------------------------------------------------ _Ptr_base的_Resetw函数 ------------------------------------------------------------
除此之外,我们还可以发现_Ptr_base中还有几个类似的函数_Resetw,这几个函数是为了被weak_ptr调用的,在这里我们不详细说,但在下面讨论_Ref_count_base 的时候会被提及。
void _Resetw()
{ // release weak reference to resource
_Resetw((_Elem *), );
} template<class _Ty2>
void _Resetw(const _Ptr_base<_Ty2>& _Other)
{ // release weak reference to resource and take _Other._Ptr
_Resetw(_Other._Ptr, _Other._Rep);
} template<class _Ty2>
void _Resetw(const _Ty2 *_Other_ptr, _Ref_count_base *_Other_rep)
{ // point to _Other_ptr through _Other_rep
_Resetw(const_cast<_Ty2*>(_Other_ptr), _Other_rep);
} template<class _Ty2>
void _Resetw(_Ty2 *_Other_ptr, _Ref_count_base *_Other_rep)
{ // point to _Other_ptr through _Other_rep
if (_Other_rep)
_Other_rep->_Incwref();
if (_Rep != )
_Rep->_Decwref();
_Rep = _Other_rep;
_Ptr = _Other_ptr;
}
--------------------------------------------------------------- _Ref_count_base ---------------------------------------------------------------
_Ref_count_base有两个虚函数,_Ref_count_base的几个子类(带析构器和带构造器)只是override了这两个函数,来产生不同的指针析构行为和自身析构行为。
virtual void _Destroy() = 0;
virtual void _Delete_this() = 0;
因此我们只需要研究_Ref_count_base本身就好。
_Ref_count_base带有两个数据成员(指针数据成员在具体子类里面)
_Atomic_counter_t _Uses;
_Atomic_counter_t _Weaks;
从名字可以猜测出来 _Uses 是shared_ptr的引用计数, _Weaks 是weak_ptr的引用计数
为什么我们需要 _Weaks 呢? 因为在_Uses 引用计数为0(最后一个shared_ptr已经被析构)的时候我们就应该析构掉真正的指针,但问题是这个引用计数对象本身也是一个指针,那么这个引用计数也要在这时候被析构吗?使用过shared_ptr的朋友会知道,shared_ptr 有一个与之紧密相连的类 weak_ptr 实际上由一个shared_ptr 产生的weak_ptr是共享同一个引用计数对象的(这样子weak_ptr就可以知道真正的指针是否被析构掉了)。如果所以 shared_ptr 都被析构掉了同时其引用计数对象,但析构掉了,但有这个 shared_ptr 产生的 weak_ptr 仍然存在那么就可能导致 weak_ptr 访问一个已经被析构的指针。 因此应该是所有的 shared_ptr 与其 产生的weak_ptr 都被析构掉了,其引用计数对象才被析构掉。
我们可以从下面的减少引用计数函数看出来。
PS: #define _MT_DECR _InterlockedIncrement(reinterpret_cast<volatile long *>(&x))
void _Decref()
{ // decrement use count
if (_MT_DECR(_Ignored, _Uses) == )
{ // destroy managed resource, decrement weak reference count
_Destroy();
_Decwref();
}
} void _Decwref()
{ // decrement weak reference count
if (_MT_DECR(_Ignored, _Weaks) == )
_Delete_this();
}
与上面相对应的增加引用计数函数
PS: #define _MT_INCR(mtx, x)_InterlockedIncrement(reinterpret_cast<volatile long *>(&x))
void _Incref()
{ // increment use count
_MT_INCR(_Ignored, _Uses);
} void _Incwref()
{ // increment weak reference count
_MT_INCR(_Ignored, _Weaks);
}
再补上 _Ref_count_base 的构造函数
_Ref_count_base()
{ // construct
_Init_atomic_counter(_Uses, );
_Init_atomic_counter(_Weaks, );
}
我们可以看到 _Ref_count_base 构造函数中对 _Uses 与 _Weaks 初始化引用计数为1,_Uses 为0时析构指针, _Weaks 为0时析构引用计数对象。
比较有趣的是我们可以从 weak_ptr 指针 lock 出一个 shared_ptr 指针的时候,会调用_Ref_count_base 类的函数 _Incref_nz,这个函数检查引用计数对象的引用计数是否为0,非零(未析构真正指针)的时候就可以增加一个引用计数。这里面为了 Lock-Free 调用了函数 _InterlockedCompareExchange。
bool _Incref_nz()
{ // increment use count if not zero, return true if successful
for (; ; )
{ // loop until state is known
#if defined(_M_IX86) || defined(_M_X64) || defined(_M_CEE_PURE)
_Atomic_integral_t _Count =
static_cast<volatile _Atomic_counter_t&>(_Uses); if (_Count == )
return (false); if (static_cast<_Atomic_integral_t>(_InterlockedCompareExchange(
reinterpret_cast<volatile long *>(&_Uses),
_Count + , _Count)) == _Count)
return (true);
#else /* defined(_M_IX86) || defined(_M_X64) || defined(_M_CEE_PURE) */
_Atomic_integral_t _Count =
_Load_atomic_counter_explicit(_Uses, memory_order_relaxed); if (_Count == )
return (false); if (_Compare_increment_atomic_counter_explicit(
_Uses, _Count, memory_order_relaxed))
return (true);
#endif /* defined(_M_IX86) || defined(_M_X64) || defined(_M_CEE_PURE) */
}
}
因为 _Ref_count_base 里面的引用计数增加/减少都是Lock-Free的,因此对shared_ptr的引用计数是多线程安全的。
--------------------------------------------------------------- shared_ptr的线程安全---------------------------------------------------------------
多个线程同时对同一个shared_ptr的写操作是不安全的,因为其swap函数
void swap(_Myt& _Other) _NOEXCEPT
{ // swap pointers
this->_Swap(_Other);
}
调用了一个非线程安全函数_Ptr_base的_Swap
void _Swap(_Ptr_base& _Right)
{ // swap pointers
_STD swap(_Rep, _Right._Rep);
_STD swap(_Ptr, _Right._Ptr);
}
但是多个线程同时对共享引用计数的不同shared_ptr的写操作是安全的,因为对于真正的指针,shared_ptr只对其进行简单的读写不修改其指向的对象的内部状态,而且同一时刻只有一个线程对某个shared_ptr真正的指针进行读写,因此线程安全的。对于引用计数对象,虽然修改了其内部状态,但本身这种修改动作是线程安全的。所以我们可以推论多个线程同时对共享引用计数的不同shared_ptr的写操作也是安全的。
boost库对shared_ptr的描述也证明了这一点。
shared_ptr objects offer the same level of thread safety as builtin types.
A shared_ptr instance can be "read" (accessed using only const operations) simultaneously by multiple threads.
Different shared_ptr instances can be "written to" (accessed using mutable operations such as operator= or reset) simultaneosly
by multiple threads (even when these instances are copies, and share the same reference count underneath.)
Any other simultaneous accesses result in undefined behavior.
翻译为中文如下:
shared_ptr 对象提供与内建类型一样的线程安全级别。一个 shared_ptr 实例可以同时被多个线程“读”(仅使用不变操作进行访问)。 不同的 shared_ptr 实例可以同时被多个线程“写入”(使用类似 operator= 或 reset 这样的可变操作进行访问)(即使这些实 例是拷贝,而且共享下层的引用计数)。
任何其它的同时访问的结果会导致未定义行为。”
C++11智能指针的更多相关文章
- c++11 智能指针 unique_ptr、shared_ptr与weak_ptr
c++11 智能指针 unique_ptr.shared_ptr与weak_ptr C++11中有unique_ptr.shared_ptr与weak_ptr等智能指针(smart pointer), ...
- C++11——智能指针
1. 介绍 一般一个程序在内存中可以大体划分为三部分——静态内存(局部的static对象.类static数据成员以及所有定义在函数或者类之外的变量).栈内存(保存和定义在函数或者类内部的变量)和动态内 ...
- C++11智能指针之std::unique_ptr
C++11智能指针之std::unique_ptr uniqut_ptr是一种对资源具有排他性拥有权的智能指针,即一个对象资源只能同时被一个unique_ptr指向. 一.初始化方式 通过new云 ...
- 【C++11新特性】 C++11智能指针之weak_ptr
如题,我们今天要讲的是C++11引入的三种智能指针中的最后一个:weak_ptr.在学习weak_ptr之前最好对shared_ptr有所了解.如果你还不知道shared_ptr是何物,可以看看我的另 ...
- 详解C++11智能指针
前言 C++里面的四个智能指针: auto_ptr, unique_ptr,shared_ptr, weak_ptr 其中后三个是C++11支持,并且第一个已经被C++11弃用. C++11智能指针介 ...
- C++11 智能指针
C++ 11标准库引入了几种智能指针 unique_ptr shared_ptr weak_ptr C++内存管理机制是当一个变量或对象从作用域过期的时候就会从内存中将他干掉.但是如果变量只是一个指针 ...
- C++11智能指针的深度理解
平时习惯使用cocos2d-x的Ref内存模式,回过头来在控制台项目中觉得c++的智能指针有点生疏,于是便重温一下.首先有请c++智能指针们登场: std::auto_ptr.std::unique_ ...
- C++11智能指针 share_ptr,unique_ptr,weak_ptr用法
0x01 智能指针简介 所谓智能指针(smart pointer)就是智能/自动化的管理指针所指向的动态资源的释放.它是存储指向动态分配(堆)对象指针的类,用于生存期控制,能够确保自动正确的销毁动 ...
- C++11智能指针原理和实现
一.智能指针起因 在C++中,动态内存的管理是由程序员自己申请和释放的,用一对运算符完成:new和delete. new:在动态内存中为对象分配一块空间并返回一个指向该对象的指针: delete:指向 ...
随机推荐
- mysqldump 安全 --skip-add-drop-table
[root@localhost data]# mysqldump -uroot --master-data=2 -p --single-transaction --skip-add-drop-ta ...
- php常用代码(一)
一:获取上个小时 方法1:date("H",strtotime("-1 hours"); 方法2:date('H',time()-60*60); 方法3:ech ...
- ubuntu thrift 0.9.3编译安装
Table of Contents 1. 下载thrift源代码 2. 编译并安装 3. 运行测试程序 4. 安装 1 下载thrift源代码 git clone https://git-wip-us ...
- 如何编写自己的Linux安全检查脚本?
因为本人工作中要涉及到很多东西,审计(日志.数据神马的).源代码审计.渗透测试.开发一大堆东西,有些东西,越是深入去做,越会发现,没有工具或脚本,工作起来是有多么的坑. 工作的这段时间,自己写了几个工 ...
- C++面向对象设计
一. 组合(复合),继承,委托 1.composition(组合)has-a 1.1 组合举例:(Adapter 设计模式) 关系: 利用deque功能实现所有queue功能 template < ...
- Inversions
There are N integers (1<=N<=65537) A1, A2,.. AN (0<=Ai<=10^9). You need to find amount o ...
- ArcGIS 投影转换(AE)
private void btnOK_Click(object sender, EventArgs e) { try { CheckError(); this.checkEdit1.Enabled = ...
- 【阿里云产品公测】云引擎ACE新手实战基于Wordpress
[阿里云产品公测]云引擎ACE新手实战基于Wordpress 作者:阿里云用户imnpc ACE(Aliyun Cloud Engine) 是一款弹性.分布式的应用托管环境,支持Java.php多种语 ...
- nodejs(一) 简单登录验证 使用mongoose 操作MongoDB
---恢复内容开始--- 开发使用webstorm 9 新建nodejs+express 项目 newfarmer 文章目录 配置Mongoose 创建目录及文件 插入数据,POST提交JSON增加 ...
- Java Lock
JVM中的另一种锁Lock的实现.与synchronized不同的是,Lock完全用Java写成,在java这个层面是无关JVM实现的.在java.util.concurrent.locks包中有很多 ...