使用通用侵入指针客户端的引用计数 [英] Reference counting with a generic intrusive pointer client

查看:185
本文介绍了使用通用侵入指针客户端的引用计数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简介



Peter Weinhart介绍了如何设计使用CRTP的通用intrusive_ptr基类,其可以如下使用:

  class foo:intrusive_base< foo> 
{
// foo专用代码。
};

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



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



控制 foo ,可能最好的方法是使用基于策略的实现,并具有引用计数和基本版本 foo 。没有对 foo 的控制,一个替代设计将反转继承关系:

  template< typename Base> 
class intrusive:public Base
{
//?

private:
std :: atomic_size_t ref_count_;
};

typedef intrusive< foo> intrusive_foo;

//假设boost :: intrusive_ptr作为插入指针实现
boost :: intrusive_ptr< intrusive_foo> x = new intrusive_foo;
{
auto y = x; //语义:boost :: intrusive_ptr_add_ref(x.get())

//在范围退出:boost :: intrusive_ptr_release(x.get())
}

在上述文章中,Peter说,一个这样的通用实现[



问题



这样一个通用入侵类的实现如何?我可以看到它可能从C ++ 11继承的构造函数中受益,但是我不清楚如何使用提到的工具实际实现 intrusive 的主体。 / p>

解决方案

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

在这种情况下,在将指针传递给不透明API和unref


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



但是为了回答主要问题,我假设他使用可变参数模板和完美的转发来定义一个构造函数,如下所示:

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

这允许你用任意数量的任何类型的参数,它们将被转发到 Base ,所以你可以用任何可以用来构造 Base



另一个替代方法是使用C ++ 11继承构造函数(未在任何编译器AFAIK中实现)

 模板< typename Base> 
class intrusive:public Base
{
使用Base :: Base;


Introduction

Peter Weinhart describes how to design a generic intrusive_ptr base class using CRTP, which may be used as follows:

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

This approach imposes the constraint that all foo objects carry a reference counter. Assume that we keep foo sometimes by value and only want to pay the price of the reference counter when we have a pointer. For example, sometimes we would like to create foo instances and just move them around, and sometimes we want to allocate foo on the heap.

Conceptually, the right mechanism for this scenario is a std::shared_ptr. However, there are certain scenarios requiring raw pointers that would call for an intrusive pointer, e.g., when passing pointers through a C API that take void pointers. In this case, one would "ref" the pointer before passing it to the opaque API and "unref" when getting it back.

Having control over foo, probably the best method would be to use a policy-based implementation and have a reference-counted and basic version of foo. Without having control over foo, an alternative design would to invert the inheritance relationship:

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())
}

In the above mentioned article, Peter says that a such a "generic implementation of [intrusive] would make use of C++0x variadic templates and perfect forwarding."

Question

How would the implementation of such a generic intrusive class look like? I could see that it may benefit from C++11 inheriting constructors, but it is unclear to me how one would in fact implement the body of intrusive using the mentioned tools.

解决方案

Using make_shared gives you the same efficiency as an intrusive pointer.

In this case, one would "ref" the pointer before passing it to the opaque API and "unref" when getting it back.

As someone else said, you can use enable_shared_from_this to get a shared_ptr back from a raw pointer (as long as there is at least one shared_ptr somewhere in the system which still owns the object)

But to answer the main question, I assume he means using variadic templates and perfect forwarding to define a constructor, which would look like:

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

This allow you to construct the intrusive with any number of arguments of any type and they will be forwarded to the Base, so you can construct it with any arguments that could be used to construct a Base.

Another alternative would be to use C++11 inheriting constructors (which aren't implemented in any compiler AFAIK)

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

这篇关于使用通用侵入指针客户端的引用计数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆