enable_shared_from_this 实现原理

前言

enable_shared_from_this 可以帮助我们用 this 指针安全地创建 shared_ptr。

enable_shared_from_this

假设我们的程序使用 shared_ptr 管理 Widget 对象,我们用一个 vector 来记录已经处理过的 Widget 对象:

std::vector<std::shared_ptr<Widget>> processedWidgets;

继续,假设 Widget 有一个用于处理的成员函数:

class Widget {
 public:
  void process() {
    // 处理 Widget
    // 然后将它添加到已处理过的 Widget 列表中
    processedWidgets.emplace_back(this);
  }
};

上面的代码可以通过编译,但是向 shared_ptr 的容器传递一个原始指针(this),shared_ptr 会由此为指向的 Widget 创建一个控制块(使用原始指针创建 shared_ptr 时会创建一个控制块来控制资源的释放)。

听起来没什么问题,直到你意识到如果成员函数外面早已存在指向那个 Widget 对象的指针,这时有多个控制块控制同一个资源,会导致资源重复释放。

shared_ptr API 中早已有处理这种情况的设施。它就是 enable_shared_from_this。如果你想创建一个用 shared_ptr 管理的类,这个类能够用 this 指针安全的创建一个 shared_ptr,enable_shared_from_this 就可作为基类的模板类。

class Widget: public std::enable_shared_from_this<Widget> {
 public:
  void process() {
    processedWidgets.emplace_back(shared_from_this());
  }
};

继承 enable_shared_from_this 后,如果想从 this 指针创建一个 shared_ptr,只需要调用 shared_from_this() 函数即可。

实现原理

enable_shared_from_this 的源码如下:

template <class _Tp>
class enable_shared_from_this {
  mutable weak_ptr<_Tp> __weak_this_;
protected:
  enable_shared_from_this() {}
  ~enable_shared_from_this() {}
public:
  shared_ptr<_Tp> shared_from_this() {
    return shared_ptr<_Tp>(__weak_this_);
  }
  shared_ptr<_Tp const> shared_from_this() const {
    return shared_ptr<const _Tp>(__weak_this_);
  }
  template <class _Up> friend class shared_ptr;
};

enable_shared_from_this 的代码看起来平平无奇,内部有一个成员 __weak_this_,当调用 shared_from_this() 时就根据这个 weak_ptr 创建一个 shared_ptr。

那是怎么用 weak_ptr 创建 shared_ptr 的,这个 __weak_this_ 又是什么时候初始化的呢,我们可以在 shared_ptr 的构造函数中找到答案。

template <class _Tp>
class shared_ptr {
 public:
  using element_type = _Tp;
 private:
  element_type*        __ptr_;
  __shared_weak_count* __cntrl_;
 public:
  template<class _Yp>
  shared_ptr(_Yp* __p)
    : __ptr_(__p) {
      __cntrl_ = new __shared_weak_count();
    __enable_weak_this(__p);
  }
  
  template<class _Yp>
  shared_ptr(const weak_ptr<_Yp>& __r)
    : __ptr_(__r.__ptr_),
      __cntrl_(__r.__cntrl_ ? __r.__cntrl_->lock() : __r.__cntrl_) {
    if (__cntrl_ == 0) {
      assert(!"bad_weak_ptr");
    }
  }
 private:
  template <class _Yp>
  void __enable_weak_this(const enable_shared_from_this<_Yp>* __e)  {
    if (__e) {
      // __e 是 Widget 类型的指针,this 是 shared_ptr<Widget> 类型的
      // 初始化它内部的 weak_ptr,以便后面根据指向的控制块创建 shared_ptr
      __e->__weak_this_ = *this;
    }
  }
};

在 shared_ptr(_Yp* __p) 中会调用 __enable_weak_this 将 enable_shared_from_this 中的 weak_ptr 赋值为当前 shared_ptr。

工作流程如下:

首先,我们的类(Widget)继承 enable_shared_from_this,此时 Widget 成员变量中多了一个 weak_ptr<Widget>,默认情况下该 weak_ptr 内部的指针都指向空。

然后,我们用 this 指针创建了一个 shared_ptr,在 shared_ptr 构造函数中,成员变量的 weak_ptr 指向刚创建的 shared_ptr。

于是当我们使用 shared_from_this() 时,会调用 shared_ptr(const weak_ptr<_Yp>& __r) 中,先将 ptr 指向 weak_ptr 指涉的资源,然后调用 __cntrl_->lock() 将控制块的引用计数加 1。

因此,如果我们想使用 shared_from_this(),必须已经存在一个指向当前对象的 shared_ptr。

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值