介绍

彼得·温哈特(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之前,它会“引用”指针,而在将其返回时,将“取消引用”。

可以控制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())
}


在上面提到的文章中,彼得说,这样的“ [intrusive]的通用实现将利用C ++ 0x可变参数模板和完美的转发”。



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

最佳答案

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


  在这种情况下,在将指针传递给不透明的API之前,它会“引用”指针,而在将其返回时,将“取消引用”。


就像其他人所说的,您可以使用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;

10-08 09:44
查看更多