由下图可知,一个shared_ptr对象,里面其实包含两个指针,一个指针指向被管理对象(manged object),一个指向管理对象(manager object),其中管理对象(manager object)中也包含被管理对象的指针,因为它要负责什么实际析构被管理对象。而shared_ptr外层也包含原始指针是为了方便*,->操作
template<typename _Tp>
class shared_ptr : public __shared_ptr<_Tp>
template<typename _Tp, _Lock_policy _Lp>
class __shared_ptr {
_Tp* _M_ptr; // Contained pointer.
__shared_count<_Lp> _M_refcount; // Reference counter.
}
template<_Lock_policy _Lp>
class __shared_count {
friend class __weak_count<_Lp>;
_Sp_counted_base<_Lp>* _M_pi;
}
template<_Lock_policy _Lp = __default_lock_policy>
class _Sp_counted_base
: public _Mutex_base<_Lp> {
// Called when _M_use_count drops to zero, to release the resources
// managed by *this.
virtual void
_M_dispose() noexcept = 0;
// Called when _M_weak_count drops to zero.
virtual void
_M_destroy() noexcept
{ delete this; }
_Atomic_word _M_use_count; // #shared
_Atomic_word _M_weak_count; // #weak + (#shared != 0)
}
template<typename _Tp, typename _Alloc, _Lock_policy _Lp>
class _Sp_counted_ptr_inplace final : public _Sp_counted_base<_Lp>
正确使用share_ptr的用法是,多个share_ptr 必须共享同一个管理对象,否则会发生一个原始指针被析构多次的问题(这首先要从shared_ptr的拷贝构造或者赋值构造说起,当一个shared_ptr对象sp2是由sp1拷贝构造或者赋值构造得来的时候,实际上构造完成后sp1内部的__shared_count对象包含的指向管理对象的指针与sp2内部的__shared_count对象包含的指向管理对象的指针是相等的,也就是说当多个shared_ptr对象来管理同一个对象时,它们共同使用同一个动态分配的管理对象。这可以从下面的__share_ptr的构造函数和__shared_count的构造函数清楚的看出。)
template<typename _Tp1>
__shared_ptr(const __shared_ptr<_Tp1, _Lp>& __r)
: _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) // never throws
{__glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)}
__shared_count&
operator=(const __shared_count& __r) // nothrow
{
_Sp_counted_base<_Lp>* __tmp = __r._M_pi;
if (__tmp != _M_pi)
{
if (__tmp != 0)
__tmp->_M_add_ref_copy();
if (_M_pi != 0)
_M_pi->_M_release();
_M_pi = __tmp;
}
}
__weak_count相关的赋值拷贝以及析构函数均只会影响到weak_count的值,对use_count没有影响;当weak_count为0时,释放管理对象。也就是说__weak_ptr不影响被管理对象的生命周期。同时由于__weak_ptr没有像__shared_ptr那样实现*,->等常见指针相关操作符,__weak_ptr不能直接操作被管理对象;
__weak_count自身间的赋值以及__shared_count对__weak_count的赋值时,它们都具有同样的指向管理对象的指针;也就是说当多个__weak_ptr和__shared_ptr指向同一个被管理对象时,它们共享同一个管理对象,这就保证了可以通过__weak_ptr可以判断__shared_ptr指向的被管理对象是否存在以及获取到被管理对象的指针。
template<typename _Tp, _Lock_policy _Lp>
class __weak_ptr {
private:
// Used by __enable_shared_from_this.
void
_M_assign(_Tp* __ptr, const __shared_count<_Lp>& __refcount) noexcept
{
_M_ptr = __ptr;
_M_refcount = __refcount;
}
template<typename _Tp1, _Lock_policy _Lp1> friend class __shared_ptr;
template<typename _Tp1, _Lock_policy _Lp1> friend class __weak_ptr;
friend class __enable_shared_from_this<_Tp, _Lp>;
friend class enable_shared_from_this<_Tp>;
_Tp* _M_ptr; // Contained pointer.
__weak_count<_Lp> _M_refcount; // Reference counter.
}
template<_Lock_policy _Lp>
class __weak_count {
friend class __shared_count<_Lp>;
_Sp_counted_base<_Lp>* _M_pi;
~__weak_count() noexcept
{
if (_M_pi != 0)
_M_pi->_M_weak_release();
}
}
template<_Lock_policy _Lp = __default_lock_policy>
class _Sp_counted_base
: public _Mutex_base<_Lp> {
_Atomic_word _M_use_count; // #shared
_Atomic_word _M_weak_count; // #weak + (#shared != 0)
}
C++引入了enable_shared_from_this利用weak_ptr的特性解决了这一问题。其基本思想是通过M继承模板类enable_shared_from_this,这样对象M内部将会有一个__weak_ptr指针_M_weak_this,在第一次创建指向M的shared_ptr Pt时,通过模板特化,将会初始化_M_weak_this;这样M内部也会产生一个指向自身的weak_ptr,并且该weak_ptr内部的管理对象与Pt的管理对象是相同的(这可以从weak_ptr内部的_M_assign函数看出)。
/**
* @brief Base class allowing use of member function shared_from_this.
*/
template<typename _Tp>
class enable_shared_from_this
{
protected:
constexpr enable_shared_from_this() noexcept { }
enable_shared_from_this(const enable_shared_from_this&) noexcept { }
enable_shared_from_this&
operator=(const enable_shared_from_this&) noexcept
{ return *this; }
~enable_shared_from_this() { }
public:
shared_ptr<_Tp>
shared_from_this()
{ return shared_ptr<_Tp>(this->_M_weak_this); }
shared_ptr<const _Tp>
shared_from_this() const
{ return shared_ptr<const _Tp>(this->_M_weak_this); }
private:
template<typename _Tp1>
void
_M_weak_assign(_Tp1* __p, const __shared_count<>& __n) const noexcept
{ _M_weak_this._M_assign(__p, __n); }
template<typename _Tp1>
friend void
__enable_shared_from_this_helper(const __shared_count<>& __pn,
const enable_shared_from_this* __pe,
const _Tp1* __px) noexcept
{
if (__pe != 0)
__pe->_M_weak_assign(const_cast<_Tp1*>(__px), __pn);
}
mutable weak_ptr<_Tp> _M_weak_this;
};
enable_shared_from_this 提供安全的替用方案,以替代 std::shared_ptr(this) 这样的表达式, 但是前提是只允许在先前已被std::shared_ptr 管理的对象上调用 shared_from_this 。因为enable_shared_from_this底层依赖的是weak_ptr,而weak_ptr需要和shared_ptr共享管理对象(manager object,所以这个manager object一定要存在)(防止this 被多次析构)。