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

时间:2012-03-05 23:22:12

标签: c++ c++11 variadic-templates crtp

简介

Peter Weinhart描述了如何设计a generic intrusive_ptr base class using CRTP,可以按如下方式使用:

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

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

从概念上讲,此方案的正确机制是std::shared_ptr。但是,某些场景需要原始指针,这些指针会调用一个侵入式指针,例如,当通过一个带有无效指针的C API传递指针时。在这种情况下,可以在将指针传递给不透明的API之前“ref”指针,并在获取指针时“reff”。

控制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的实体。

1 个答案:

答案 0 :(得分:0)

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

  

在这种情况下,人们会在将指针传递给不透明的API之前“引用”指针,并在获取指针时“reff”。

正如其他人所说,您可以使用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,因此您可以使用任何可用于构造a的参数来构造它Base

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

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