《C++那些事》之enable_shared_from_this
std::enable_shared_from_this它被用作需要创建与现有对象共享所有权的 std::shared_ptr
实例的类的基类。
使用 enable_shared_from_this
的类必须继承自 enable_shared_from_this
。
当一个类 A
继承了 std::enable_shared_from_this<A>
,并在某个地方创建了一个 std::shared_ptr<A>
的智能指针时,通过调用 shared_from_this
函数可以得到一个指向该对象的 std::shared_ptr
,且该 std::shared_ptr
与原始的 std::shared_ptr
共享对象的所有权。
例如:
class Foo
: public std::enable_shared_from_this<Foo>
{
}
简单实现如下
std::enable_shared_from_this
是一个模板类,定义如下:
template<class T>
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;
~enable_shared_from_this();
public:
shared_ptr<T> shared_from_this();
shared_ptr<const T> shared_from_this() const;
};
enable_shared_from_this
模板类的实现依赖于两个关键类,即 std::shared_ptr
和 std::weak_ptr
。它的核心思想是通过将 std::shared_ptr
对象作为类成员变量保存,并在需要共享该对象所有权的地方返回一个指向该对象的 std::shared_ptr
。
在 enable_shared_from_this
类的构造函数中,将 weak_this
成员变量初始化为一个空的 std::weak_ptr
。该成员变量用于保存指向该类的 std::shared_ptr
对象,该对象是通过调用 shared_from_this
函数返回的。
标准库的std::enable_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); }
#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11
#define __cpp_lib_enable_shared_from_this 201603
weak_ptr<_Tp>
weak_from_this() noexcept
{ return this->_M_weak_this; }
weak_ptr<const _Tp>
weak_from_this() const noexcept
{ return this->_M_weak_this; }
#endif
private:
template<typename _Tp1>
void
_M_weak_assign(_Tp1* __p, const __shared_count<>& __n) const noexcept
{ _M_weak_this._M_assign(__p, __n); }
// Found by ADL when this is an associated class.
friend const enable_shared_from_this*
__enable_shared_from_this_base(const __shared_count<>&,
const enable_shared_from_this* __p)
{ return __p; }
template<typename, _Lock_policy>
friend class __shared_ptr;
mutable weak_ptr<_Tp> _M_weak_this;
};
在构造函数中,weak_this_
被初始化为一个空的 std::weak_ptr
。在使用 shared_from_this
函数时,它将返回一个指向 this
对象的 std::shared_ptr
,如果此时没有任何 std::shared_ptr
对象管理该对象,将会抛出 std::bad_weak_ptr
异常。
需要注意的是,shared_from_this
函数必须在至少存在一个 std::shared_ptr
对象管理该对象时才能调用,否则将会出现未定义的行为。同时,shared_from_this
函数也不能在对象的构造函数中被调用,因为此时还没有任何 std::shared_ptr
对象管理该对象。
M_weak_this_
是一个 std::weak_ptr
对象,它保存的是指向当前对象的一个弱引用(weak reference),而不是强引用(shared reference)。
在 std::enable_shared_from_this
的实现中,wM_eak_this_
被初始化为一个空的 std::weak_ptr
,因为此时还没有任何 std::shared_ptr
对象管理当前对象,所以也就无法通过任何 std::shared_ptr
对象来创建一个指向当前对象的 std::shared_ptr
。
当我们在某个地方创建了一个 std::shared_ptr
对象来管理当前对象时,我们需要在这个 std::shared_ptr
对象创建之后,调用 std::enable_shared_from_this
中提供的 shared_from_this
函数来获得一个指向当前对象的 std::shared_ptr
。在这个过程中,shared_from_this
函数将使用 _M_weak_this
中保存的弱引用来创建一个指向当前对象的 std::shared_ptr
。
需要注意的是,如果在任何一个时刻,没有任何 std::shared_ptr
对象管理当前对象,那么 _M_weak_this
中保存的弱引用就会被销毁,此时再尝试通过 shared_from_this
函数来创建一个指向当前对象的 std::shared_ptr
,将会抛出 std::bad_weak_ptr
异常。因此,使用 std::enable_shared_from_this
时需要特别注意对象的生命周期和 shared_ptr
的管理方式。
enable_shared_from_this可以使用是在shared_ptr构造过程中,有相应的设置过程。
shared_ptr调用构造__shared_ptr
,__shared_ptr
构造会调用执行_M_enable_shared_from_this_with
,_M_enable_shared_from_this_with
调用执行__base->_M_weak_assign
的过程,此时会构造_M_weak_this
。