C++ 如何使用shared_ptr来管理已引用计数的托管对象?

C++ 如何使用shared_ptr来管理已引用计数的托管对象?,c++,c++11,memory,C++,C++11,Memory,如果一个对象已被引用计数(如C中的glib),具有obj_ref,obj_unref。我们只有一个类似于obj*p的指针 我们如何使用c++的shared_ptr来管理对象,从而获得统一的接口 好吧,看来很多人误解了我的意图 这里最大的问题不是关于deleter。这是关于通知原经理我增加了refcount 如果我分配或复制,只有std::shared_ptr增加了引用计数,但原始的没有。还有什么可以告诉它的吗?因此,正如unref操作一样。在多个智能指针实现中使用相同的对象是一个非常糟糕的主意

如果一个对象已被引用计数(如C中的glib),具有
obj_ref
obj_unref
。我们只有一个类似于
obj*p
的指针

我们如何使用c++的
shared_ptr
来管理对象,从而获得统一的接口


好吧,看来很多人误解了我的意图

这里最大的问题不是关于deleter。这是关于通知原经理我增加了refcount


如果我分配或复制,只有
std::shared_ptr
增加了引用计数,但原始的没有。还有什么可以告诉它的吗?因此,正如unref操作一样。

在多个智能指针实现中使用相同的对象是一个非常糟糕的主意,因为它们的ref计数无法相互了解。一旦其中一个引用计数为零,它将删除该对象,即使另一个仍然保留引用

如果你真的需要的话,你可以用定制的删除器构造你的智能指针(什么也不做),但是我真的不推荐这种方法


选择一个实现并坚持它。

在多个智能指针实现中使用相同的对象是一个非常糟糕的主意,因为它们的引用计数不能相互了解。一旦其中一个引用计数为零,它将删除该对象,即使另一个仍然保留引用

如果你真的需要的话,你可以用定制的删除器构造你的智能指针(什么也不做),但是我真的不推荐这种方法


选择一个实现并坚持它。

std::shared_ptr
允许您传递一个自定义的deleter,在销毁所拥有的对象时调用该deleter。您可以使用它调用
obj\u unref

obj* p = create_obj();
p->obj_ref();
std::shared_ptr<obj> sp(p, [](auto p) {
        p->obj_unref();
    });
/* use sp normally, obj will be 'obj_unref'ed and deleted when sp goes out of scope */
obj*p=create_obj();
p->obj_ref();
std::共享的ptr sp(p,[](自动p){
p->obj_unref();
});
/*正常使用sp,当sp超出范围时,obj将被“取消”并删除*/
我不知道当计数达到0时,
obj
是如何创建的,以及它是否被
obj\u unref()
破坏,但我希望你明白我的意思。

其思想是在开始时只增加
obj
s内部引用计数一次,在销毁最后一个
shared\u ptr
时只减少一次。

std::shared\u ptr
允许您传递一个自定义的deleter,该deleter在销毁所属对象时调用。您可以使用它调用
obj\u unref

obj* p = create_obj();
p->obj_ref();
std::shared_ptr<obj> sp(p, [](auto p) {
        p->obj_unref();
    });
/* use sp normally, obj will be 'obj_unref'ed and deleted when sp goes out of scope */
obj*p=create_obj();
p->obj_ref();
std::共享的ptr sp(p,[](自动p){
p->obj_unref();
});
/*正常使用sp,当sp超出范围时,obj将被“取消”并删除*/
我不知道当计数达到0时,
obj
是如何创建的,以及它是否被
obj\u unref()
破坏,但我希望你明白我的意思。

其思想是在开始时只增加
obj
s内部引用计数一次,在最后一个
shared\u ptr
被破坏时只减少它一次。

最简单的方法,最小的破坏性方法,就是简单地为对象编写自己的外观,将底层对象作为私有成员,并提供简单的包装器来访问它


然后使用一个
std::shared\u ptr

最简单的方法,入侵最小,破坏可能性最小的方法,就是简单地为对象编写自己的外观,底层对象作为私有成员,并提供简单的包装来访问它


然后使用一个
std::shared\u ptr
来达到这个目的。

不要试图以某种方式将std::shared\u ptr
引用到您的自定义引用,这不会有好的结局。只需编写一个自定义指针:

struct objPtr {

    objPtr()
    : _ptr{nullptr} { }

    objPtr(obj *ptr)
    : _ptr{ptr} {
        if(_ptr)
            _ptr->obj_ref();
    }

    ~objPtr() {
        if(_ptr)
            _ptr->obj_unref();
    }

    objPtr(objPtr const &orig)
    : objPtr{orig._ptr} { }

    objPtr &operator = (objPtr const &orig) {
        obj *const oPtr = std::exchange(_ptr, orig._ptr);

        _ptr->obj_ref();
        oPtr->obj_unref();

        return *this;
    }

    obj &operator * () { return *_ptr; }
    obj const &operator * () const { return *_ptr; }

    obj *operator -> () { return _ptr; }
    obj const *operator -> () const { return _ptr; }

    operator bool() const { return _ptr; }
    bool operator ! () const { return !_ptr; }

private:
    obj *_ptr;
};

如果您愿意,请添加移动构造和分配。

不要试图以某种方式将胶带
std::shared\u ptr
的引用添加到自定义的引用中,这样不会有好的结果。只需编写一个自定义指针:

struct objPtr {

    objPtr()
    : _ptr{nullptr} { }

    objPtr(obj *ptr)
    : _ptr{ptr} {
        if(_ptr)
            _ptr->obj_ref();
    }

    ~objPtr() {
        if(_ptr)
            _ptr->obj_unref();
    }

    objPtr(objPtr const &orig)
    : objPtr{orig._ptr} { }

    objPtr &operator = (objPtr const &orig) {
        obj *const oPtr = std::exchange(_ptr, orig._ptr);

        _ptr->obj_ref();
        oPtr->obj_unref();

        return *this;
    }

    obj &operator * () { return *_ptr; }
    obj const &operator * () const { return *_ptr; }

    obj *operator -> () { return _ptr; }
    obj const *operator -> () const { return _ptr; }

    operator bool() const { return _ptr; }
    bool operator ! () const { return !_ptr; }

private:
    obj *_ptr;
};

如果您愿意,可以添加移动构造和分配。

如果您想要
共享的\u ptr
,请从
唯一的\u ptr
开始。然后建立

struct cleanup_obj {
  // not called with nullptr:
  void operator()(obj* t)const {
    obj_unref(t);
  }
};
using obj_unique_ptr = std::unique_ptr<T, cleanup_obj>;
using obj_shared_ptr = std::shared_ptr<T>;
template<class T>
obj_unique_ptr<T> make_unique_refcount( T* t ) {
  using ptr=obj_unique_ptr<T>;
  if (!t) return ptr();
  obj_ref(t);
  return ptr(t);
}
template<class T>
obj_shared_ptr<T> make_shared_refcount( T* t ) {
  return make_unique_refcount(t); // implicit convert does right thing
}
我想这就够了。现在它是一个零开销的引用计数侵入式智能指针。这些侵入式智能指针可以通过隐式转换转换为
std::shared_ptr
,因为它们仍然是
唯一的_ptr
s。它们只是我们教过的复制它们自己的独一无二的东西

它确实需要从
obj_refcount_ptr
移动以获得
shared_ptr
。我们可以解决这个问题:

operator std::shared_ptr<T>() const {
  return obj_refcount_ptr(*this);
}
运算符std::shared_ptr()常量{
返回obj_refcount_ptr(*此项);
}
创建此的
obj_refcount_ptr
副本,并将其移动到
共享_ptr
。只调用一个add ref,而remove ref仅在
shared\u ptr
计数变为零时调用



一般的方法是从最简单的智能指针(
unique\u ptr
)开始,正确使用它,然后利用它的实现来获得
shared\u ptr
,最后是
refcount\u ptr
。我们可以单独测试
unique\u ptr
实现,它的正确性使测试更丰富的指针更容易。

如果您想要
共享的\u ptr
,请从
unique\u ptr
开始。然后建立

struct cleanup_obj {
  // not called with nullptr:
  void operator()(obj* t)const {
    obj_unref(t);
  }
};
using obj_unique_ptr = std::unique_ptr<T, cleanup_obj>;
using obj_shared_ptr = std::shared_ptr<T>;
template<class T>
obj_unique_ptr<T> make_unique_refcount( T* t ) {
  using ptr=obj_unique_ptr<T>;
  if (!t) return ptr();
  obj_ref(t);
  return ptr(t);
}
template<class T>
obj_shared_ptr<T> make_shared_refcount( T* t ) {
  return make_unique_refcount(t); // implicit convert does right thing
}
我想这就够了。现在它是一个零开销的引用计数侵入式智能指针。这些侵入式智能指针可以通过隐式转换转换为
std::shared_ptr
,因为它们仍然是
唯一的_ptr
s。它们只是我们教过的复制它们自己的独一无二的东西

它确实需要从
obj_refcount_ptr
移动以获得
shared_ptr
。我们可以解决这个问题:

operator std::shared_ptr<T>() const {
  return obj_refcount_ptr(*this);
}
运算符std::shared_ptr()常量{
返回对象参考计数