0

我的程序将创建和删除很多对象(来自 REST API)。这些对象将被多个地方引用。我想要一个“内存缓存”并通过引用计数来管理对象的生命周期,以便在不再使用它们时可以释放它们。

所有对象都继承自一个基类Ressource

主要Cache是一个std::map<_key_, std::shared_ptr<Ressource> >

然后我很困惑,怎么Cache知道Ressource引用计数何时减少?IE。调用std::shared_ptr destructoror operator=

1/ 我不想遍历 std::map 并检查每个 ref.count()。

2/ 我可以重用 std::shared_ptr 并实现自定义钩子吗?

class RessourcePtr : public std::shared_ptr<Ressource>
...

3/ 我应该实现自己的引用计数类吗?前任。https://stackoverflow.com/a/4910158/1058117

谢谢!

4

4 回答 4

1

您可以将 amap<Key, weak_ptr<Resource> >用于您的字典。

它的工作原理大致如下:

map<Key, weak_ptr<Resource> > _cache;

shared_ptr<Resource> Get(const Key& key)
{
    auto& wp = _cache[key];
    shared_ptr<Resource> sp; // need to be outside of the "if" scope to avoid
                             // releasing the resource
    if (wp.expired()) {
        sp = Load(key); // actually creates the resource
        wp = sp;
    }

    return wp.lock();
}

当所有shared_ptr返回Get的对象都被销毁时,对象将被释放。缺点是,如果您使用一个对象然后立即销毁共享指针,那么您并没有真正使用缓存,正如@pmr 在他的评论中所建议的那样。

编辑:您可能知道,此解决方案不是线程安全的,您需要锁定对map对象的访问。

于 2013-01-26T12:50:16.967 回答
1

make shared_ptr not use delete展示了如何为共享指针提供自定义删除功能。

如果您想要使用客户函数进行引用添加和删除,您也可以使用侵入式指针。

于 2013-01-26T12:52:37.900 回答
1

问题是,在您的场景中,池将保持每个引用都处于活动状态。这是一个从引用计数为 1 的池中删除资源的解决方案。问题是,何时修剪池。此解决方案将在每次调用get. 这样,“再次发布并获取”之类的场景将很快。

#include <memory>
#include <map>
#include <string>
#include <iostream>

struct resource {

};

class pool {
public:
  std::shared_ptr<resource> get(const std::string& x) 
  {
    auto it = cache_.find(x);
    std::shared_ptr<resource> ret;

    if(it == end(cache_))
      ret = cache_[x] = std::make_shared<resource>();
    else {
      ret = it->second;
    }
    prune();

    return ret;
  }

  std::size_t prune() 
  {
    std::size_t count = 0;
    for(auto it = begin(cache_); it != end(cache_);)
    {
      if(it->second.use_count() == 1) {
        cache_.erase(it++);
        ++count;
      } else {
        ++it;
      }
    }
    return count;
  }

  std::size_t size() const { return cache_.size(); }

private:
  std::map<std::string, std::shared_ptr<resource>> cache_;
};

int main()
{
  pool c;
  {
    auto fb = c.get("foobar");
    auto fb2 = c.get("foobar");
    std::cout << fb.use_count() << std::endl;
    std::cout << "pool size: " << c.size() << std::endl;
  }
  auto fb3 = c.get("bar");
  std::cout << fb3.use_count() << std::endl;
  std::cout << "pool size: " << c.size() << std::endl;
  return 0;
}
于 2013-01-26T13:06:01.480 回答
0

你不想要一个缓存你想要一个池。特别是对象池。您的主要问题不是如何实现引用计数,shared_ptr 已经为您做到了。当不再需要某个资源时,您只需将其从缓存中删除即可。您的主要问题将是由于不断分配/删除导致的内存碎片以及由于全局内存分配器中的争用而导致的缓慢。查看线程特定的内存池实现以获得答案。

于 2013-01-26T12:54:13.247 回答