使用通用侵入式指针客户端进行引用计数

Reference counting with a generic intrusive pointer client

本文关键字:引用 客户端 指针      更新时间:2023-10-16

简介

Peter Weinhart描述了如何使用CRTP设计一个通用的intrusive_ptr基类,它可以如下使用:

class foo : intrusive_base<foo>
{
     // foo-specific code.
};

这种方法施加了所有foo对象都携带引用计数器的约束。假设我们有时按值保留foo,并且只想在有指针时支付引用计数器的价格。例如,有时我们希望创建foo实例并将它们四处移动,有时我们还希望在堆上分配foo

从概念上讲,该场景的正确机制是std::shared_ptr。然而,在某些情况下,需要原始指针来调用侵入式指针,例如,当通过采用无效指针的C API传递指针时。在这种情况下,在将指针传递给不透明的API之前,将"ref"指针,在将其返回时,将"unref"指针。

要控制foo,最好的方法可能是使用基于策略的实现,并拥有foo的引用计数和基本版本。在不控制foo的情况下,另一种设计将颠倒继承关系:

template <typename Base>
class intrusive : public Base
{
    // ?
private:
    std::atomic_size_t ref_count_;   
};
typedef intrusive<foo> intrusive_foo;
// Assume boost::intrusive_ptr as intrusive pointer implementation
boost::intrusive_ptr<intrusive_foo> x = new intrusive_foo;
{
    auto y = x;   // Semantics: boost::intrusive_ptr_add_ref(x.get())
    // At scope exit: boost::intrusive_ptr_release(x.get())
}

在上面提到的文章中,Peter说这样一个"[intrusive]的通用实现将使用C++0x可变模板和完美的转发。"

问题

这样一个通用的intrusive类的实现会是什么样子?我可以看到它可能受益于C++11继承构造函数,但我不清楚如何使用上述工具来实现intrusive的主体。

使用make_shared可以获得与侵入式指针相同的效率。

在这种情况下,将指针传递到不透明的API之前"ref"指针,并在将其返回时"unref"指针

正如其他人所说,您可以使用enable_shared_from_this从原始指针获取shared_ptr(只要系统中某个位置至少有一个shared_ptr仍然拥有该对象)

但为了回答主要问题,我认为他的意思是使用可变模板和完美转发来定义构造函数,它看起来像:

template <typename Base>
  class intrusive : public Base
  {
    template<typename... Args>
      intrusive(Args&&... args)
      : Base(std::forward<Args>(args)...), ref_count_(0)
      { }

这允许您使用任意数量的任何类型的参数来构造intrusive,这些参数将被转发到Base,因此您可以使用可用于构造Base的任何参数来构造它。

另一种选择是使用C++11继承构造函数(在任何编译器AFAIK中都没有实现)

template <typename Base>
  class intrusive : public Base
  {
    using Base::Base;