简体   繁体   English

std::shared_ptr 自定义引用计数器

[英]std::shared_ptr custom reference counter

I'm currently working on a code where I'll need to statically share an instance of an object between multiple parts of my code.我目前正在处理一个代码,我需要在代码的多个部分之间静态共享一个对象的实例。 So basically a singleton.所以基本上是一个单身人士。 This instance will be shared until no one uses it anymore.这个实例将被共享,直到没有人再使用它。 At this point I need to perform some cleanup operation before deleting the actual instance.此时我需要在删除实际实例之前执行一些清理操作。

If someone asks for the shared instance after this point, it will get a newly created one and so on.如果有人在此之后请求共享实例,它将获得一个新创建的实例,依此类推。

So I wrote something like this:所以我写了这样的东西:

template<typename F>
struct static_filter
{
  template<typename ...Args>
  static std::shared_ptr<F> get(Args... a)
  {
    return _inst = _inst ?: std::shared_ptr<F>(new F(a...));
  }

  static void cleanup()
  {
    // some cleanup operation over inst
    _inst.reset();
  }

private:
  static std::shared_ptr<F> _inst;
};

template<typename F> std::shared_ptr<F> static_filter<F>::_inst{nullptr};

And now I'm looking in a way to automatically detect when nobody is using _inst anymore.现在我正在寻找一种自动检测何时没有人使用 _inst 的方法。 Basically, I'd like to get a callback each time the use_count() of _inst falls to 1. At this point I would be able to cleanup & reset.基本上,每次 _inst 的 use_count() 下降到 1 时,我都想得到一个回调。此时我将能够清理和重置。

I'd like to avoid implementing my own reference counting for this (the application is using shared_ptr everywhere and it will be kinda tiresome to change to a custom type).我想避免为此实现我自己的引用计数(应用程序在任何地方都使用 shared_ptr 并且更改为自定义类型会有点烦人)。

I tried using a custom deleter on my instance, something along the lines of:我尝试在我的实例上使用自定义删除器,大致如下:

template<typename F>
struct static_filter
{
  template<typename ...Args>
  static std::shared_ptr<F> get(Args... a)
  {
    return _inst = _inst ?: std::shared_ptr<F>(new F(a..., **static_filter<F>::cleanup**));
  }

  static void cleanup()
  {
    // some cleanup operation over inst
    _inst.reset();
  }

private:
  static std::shared_ptr<F> _inst;
};

template<typename F> std::shared_ptr<F> static_filter<F>::_inst{nullptr};

But obviously this did not work as my ref counter never did actually reach 0.但显然这不起作用,因为我的参考计数器实际上从未达到 0。

Does anyone knows if there is a way to achieve this using shared_ptr ?有谁知道是否有办法使用 shared_ptr 实现这一目标?

Thanks.谢谢。

Your use of shared_ptr here is wrong on a semantic level.您在此处使用shared_ptr在语义级别上是错误的。 You do not want to hold ownership in this static variable but only observe through it.您不想持有此static变量的所有权,而只想通过它进行观察。 This is the use case for std::weak_ptr .这是std::weak_ptr的用例。 With this a static variable you can observe the object, return it as a shared_ptr if it exists and do not interefere with its destruction, when others hold a reference to it.有了这个静态变量,您可以观察对象,如果它存在,则将其作为shared_ptr返回,并且当其他人持有对它的引用时,不会干扰它的销毁。

This would look as follows:这将如下所示:

template<typename F>
struct static_filter
{
  template<typename ...Args>
  static std::shared_ptr<F> get(Args... a)
  {
    // Returns the shared_ptr observed, if it exists and is not expired, empty ptr otherwise
    // is atomic
    auto shared = _inst.lock(); 
    if(!shared) {
        _inst = (shared = std::shared_ptr<F>(new F(a..., **static_filter<F>::cleanup**));
    }
    return shared;
  }

  static void cleanup()
  {
    // Always check if the calling object is really the managed object
    // some cleanup operation over inst
    _inst.reset();
  }

private:
  static std::weak_ptr<F> _inst;
};

template<typename F> std::weak_ptr<F> static_filter<F>::_inst{};

Note that this is not thread safe (your code before was not thread safe, either), since two simultaneous calls to get when the pointer is empty, can both see that the pointer is empty and both construct a new object of type F .请注意,这不是线程安全的(您之前的代码也不是线程安全的),因为在指针为空时对get两个同时调用,都可以看到指针为空,并且都构造了一个F类型的新对象。 You will have to add an std::lock_guard to avoid this.您将不得不添加std::lock_guard以避免这种情况。

Note that even if you could add a callback on use_count == 1 , this would be inherently unsafe.请注意,即使您可以在use_count == 1上添加回调,这本质上也是不安全的。 This is why std::shared_ptr::unique() is deprecated from C++17 onwards and is removed in C++20 (see here and here )这就是为什么std::shared_ptr::unique()从 C++17 开始被弃用并在 C++20 中被删除(见 这里这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM