丰台网站建设联系方式/发表文章的平台有哪些
(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)
1. 关于weak_ptr:
weak_ptr也是一个很有意思的智能指针,感觉它不太像是一个智能指针,更像是一个shared_ptr的经纪人;
weak_ptr指向一个由shared_ptr管理的对象,注意一定是由shared_ptr管理的对象;
weak_ptr本身不能持有对象,如果shared_ptr管理的生命周期结束了,就相当于指向一个已销毁的对象了。
weak_ptr通过转换为shared_ptr,来访问指向的对象:也就是weak_ptr并不能直接访问到指向对象,是要借由shared_ptr进行中转,才能指向对象,访问对象。
std::weak_ptr is a smart pointer that holds a non-owning (“weak”) reference to an object that is managed by std::shared_ptr.
It must be converted to std::shared_ptr in order to access the referenced object.
2. weak_ptr实现:
下面结合windows下,vs2015中对weak_ptr的代码实现,我们看一看;
先关注weak_ptr的其中几个构造函数,可以看到函数中有调用一个_Weakly_construct_from的函数:
weak_ptr(const weak_ptr& _Other) noexcept{ // construct weak_ptr object for resource pointed to by _Otherthis->_Weakly_construct_from(_Other);}template<class _Ty2,enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>weak_ptr(const shared_ptr<_Ty2>& _Other) noexcept{ // construct weak_ptr object for resource owned by _Otherthis->_Weakly_construct_from(_Other);}
这个从父类继承的_Weakly_construct_from函数,里面有什么样的实现呢?
在获取到外部_Rep<_Ref_count_base>后,增加_Incwref了_Weaks的计数
template<class _Ty2>void _Weakly_construct_from(const _Ptr_base<_Ty2>& _Other){ // implement weak_ptr's ctorsif (_Other._Rep){_Other._Rep->_Incwref();}_Ptr = _Other._Ptr;_Rep = _Other._Rep;}
_Rep<_Ref_count_base>来源与哪?要从weak_ptr的继承关系看起:
- weak_ptr也继承自_Ptr_base
// CLASS TEMPLATE weak_ptr
template<class _Ty>
class weak_ptr: public _Ptr_base<_Ty>
- _Ptr_base是一个基类,没有继承;_Ptr_base含有两个指针元素,一个指向元素,一个指向计数类;
// CLASS TEMPLATE _Ptr_base
template<class _Ty>
class _Ptr_base
{
...
private:element_type * _Ptr{nullptr};_Ref_count_base * _Rep{nullptr};
...
}
- _Ref_count_base也是一个基类,无继承;_Ref_count_base有两个atomic元素,一个是_Uses, 一个是_Weaks;
里面提供了Incref增加_Uses计数,Incwref增加_Weaks计数;
里面提供了Decwref来尝试检查,通过_Weaks计数检查,检查是否删除自身;
里面提供了Decref来在_Uses计数为0时,调用_Destory来删除指向的对象,也会调用_Decwref来尝试看看要不要删除自身;
疑问点,Decref时,当Dec到0时,为什么会调用_Decwref呢?
这个点是因为,当_Ref_count_base构造时,首先给_Weaks赋值为1,先添加了一个自身的引用计数,这样对于_Uses计数到0时,就要计划把构造时设定的1去除掉;
同时呢,也适应了外部是否有使用weak_ptr来给_Weaks增加计数的情况。
// CLASS _Ref_count_base
class __declspec(novtable) _Ref_count_base
{
..._Atomic_counter_t _Uses;_Atomic_counter_t _Weaks;_Ref_count_base() : _Uses(1), _Weaks(1) // non-atomic initializations{// construct}void _Incref(){ // increment use count_MT_INCR(_Uses);}void _Incwref(){ // increment weak reference count_MT_INCR(_Weaks);}void _Decref(){ // decrement use countif (_MT_DECR(_Uses) == 0){ // destroy managed resource, decrement weak reference count_Destroy();_Decwref();}}void _Decwref(){ // decrement weak reference countif (_MT_DECR(_Weaks) == 0){_Delete_this();}}
...
}
3. weak_pt分析:
基于上面的_Ref_count_base的_Incref/_Incwref/_Decref/_Decwref实现,我们就能联想到很多点了。
-
有了_Weaks的计数,就能控制_Ref_count_base删除自身的时间。
虽然不能控制指向对象的释放,但_Ref_count_base自身的保留,也就可以帮助我们查询资源是否已经释放了;
也还可以通过_Ref_count_base查询_Uses计数,查询_Weaks计数。 -
所以,为什么weak_ptr虽然ref到shared_ptr,但却会不依赖shared_ptr独立存在,秘密就在此了。
weak_ptr指向shared_ptr对应的_Ref_count_base,并对_Weaks进行了计数;
这样一层弱引用的保持,虽然不持有指向资源,不对指向资源释放产生影响,但却可以了解到资源的计数信息;
这也就足够支撑weak_ptr的功能了。
这样,再来看weak_ptr主要提供的方法就简单了:
- expried用来检查指向资源是否已经清除,通过检查指向_Ref_count_base的_Uses计数来判定。
_NODISCARD bool expired() const noexcept{ // return true if resource no longer existsreturn (this->use_count() == 0);}
- lock()方法创建一个shared_ptr对象,然后调用share_ptr::_Construct_from_weak方法,来通过_Ref_count_base上的信息来构造shared_ptr对象;
如果_Uses已经为0,则构造出的shared_ptr指向为空;
如果_Uses不为0,则对_Uses计数继续增加,然后构造shared_ptr成功,返回持有资源的shared_ptr,供外部访问指向资源。
注意:实现_Incref_nz(increase reference if none zero)方法很有技巧,要借助类似CAS(compare_and_swap)类似原子方法进行实现。
_NODISCARD shared_ptr<_Ty> lock() const noexcept{ // convert to shared_ptrshared_ptr<_Ty> _Ret;(void) _Ret._Construct_from_weak(*this);return (_Ret);}---from _Ptr_basetemplate<class _Ty2>bool _Construct_from_weak(const weak_ptr<_Ty2>& _Other){ // implement shared_ptr's ctor from weak_ptr, and weak_ptr::lock()if (_Other._Rep && _Other._Rep->_Incref_nz()){_Ptr = _Other._Ptr;_Rep = _Other._Rep;return (true);}return (false);}---from _Ref_count_base: increase reference if none zero.bool _Incref_nz(){ // increment use count if not zero, return true if successfulfor (;;){ // loop until state is known#if _USE_INTERLOCKED_REFCOUNTINGconst _Atomic_integral_t _Count =static_cast<volatile _Atomic_counter_t&>(_Uses);if (_Count == 0)return (false);if (static_cast<_Atomic_integral_t>(_InterlockedCompareExchange(reinterpret_cast<volatile long *>(&_Uses),static_cast<long>(_Count + 1), static_cast<long>(_Count))) == _Count)return (true);#else /* _USE_INTERLOCKED_REFCOUNTING */const _Atomic_integral_t _Count =_Load_atomic_counter(_Uses);if (_Count == 0)return (false);if (_Compare_increment_atomic_counter(_Uses, _Count))return (true);#endif /* _USE_INTERLOCKED_REFCOUNTING */}
附录:weak_ptr源码
weak_ptr的实现代码不算很多,下面全列出来,供参考。
// CLASS TEMPLATE weak_ptr
template<class _Ty>class weak_ptr: public _Ptr_base<_Ty>{ // class for pointer to reference counted resource
public:constexpr weak_ptr() noexcept{ // construct empty weak_ptr object}weak_ptr(const weak_ptr& _Other) noexcept{ // construct weak_ptr object for resource pointed to by _Otherthis->_Weakly_construct_from(_Other);}template<class _Ty2,enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>weak_ptr(const shared_ptr<_Ty2>& _Other) noexcept{ // construct weak_ptr object for resource owned by _Otherthis->_Weakly_construct_from(_Other);}template<class _Ty2,enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>weak_ptr(const weak_ptr<_Ty2>& _Other) noexcept{ // construct weak_ptr object for resource pointed to by _Otherthis->_Weakly_construct_from(_Other.lock());}weak_ptr(weak_ptr&& _Other) noexcept{ // move construct from _Otherthis->_Move_construct_from(_STD move(_Other));}template<class _Ty2,enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>weak_ptr(weak_ptr<_Ty2>&& _Other) noexcept{ // move construct from _Otherthis->_Weakly_construct_from(_Other.lock());_Other.reset();}~weak_ptr() noexcept{ // release resourcethis->_Decwref();}weak_ptr& operator=(const weak_ptr& _Right) noexcept{ // assign from _Rightweak_ptr(_Right).swap(*this);return (*this);}template<class _Ty2>weak_ptr& operator=(const weak_ptr<_Ty2>& _Right) noexcept{ // assign from _Rightweak_ptr(_Right).swap(*this);return (*this);}weak_ptr& operator=(weak_ptr&& _Right) noexcept{ // move assign from _Rightweak_ptr(_STD move(_Right)).swap(*this);return (*this);}template<class _Ty2>weak_ptr& operator=(weak_ptr<_Ty2>&& _Right) noexcept{ // move assign from _Rightweak_ptr(_STD move(_Right)).swap(*this);return (*this);}template<class _Ty2>weak_ptr& operator=(const shared_ptr<_Ty2>& _Right) noexcept{ // assign from _Rightweak_ptr(_Right).swap(*this);return (*this);}void reset() noexcept{ // release resource, convert to null weak_ptr objectweak_ptr().swap(*this);}void swap(weak_ptr& _Other) noexcept{ // swap pointersthis->_Swap(_Other);}_NODISCARD bool expired() const noexcept{ // return true if resource no longer existsreturn (this->use_count() == 0);}_NODISCARD shared_ptr<_Ty> lock() const noexcept{ // convert to shared_ptrshared_ptr<_Ty> _Ret;(void) _Ret._Construct_from_weak(*this);return (_Ret);}};
(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)