如果没有更多引用,如何从缓存中删除(非侵入式)智能指针?

dwn*_*dwn 14 c++ caching smart-pointers shared-ptr weak-ptr

由于我的noob声誉,我无法回复此主题,特别是接受的答案:

我从未使用过boost :: intrusive智能指针,但如果你使用shared_ptr智能指针,你可以使用weak_ptr对象作为缓存.

当系统决定释放内存时,那些weak_ptr指针不算作引用,但只要该对象尚未被删除,它就可用于检索shared_ptr.

这当然是一个直观的想法,但是,C++标准不支持weak_ptrs的比较,因此它不能用作关联容器的键.这可以通过为weak_ptrs实现比较运算符来规避:

template<class Ty1, class Ty2>
    bool operator<(
        const weak_ptr<Ty1>& _Left,
        const weak_ptr<Ty2>& _Right
    );
Run Code Online (Sandbox Code Playgroud)

这个解决方案的问题是

(1)比较运算符必须获得每次比较的所有权(即从weak_ptr refs创建shared_ptrs)

(2)当管理资源的最后一个shared_ptr被破坏时,weak_ptr不会从缓存中删除,但是过期的weak_ptr会保留在缓存中.

对于(2),我们可以提供自定义析构函数(DeleteThread),但是,这将需要再次从要删除的T*创建weak_ptr,然后可以使用它从缓存中擦除weak_ptr.

我的问题是,如果有更好的方法使用智能指针缓存(我使用VC100编译器,没有提升),或者我根本没有得到它?

干杯,丹尼尔

Mat*_* M. 2

问题是,您的Cache对象不是由缓存本身寻址的,否则它将毫无用处。

a 的想法Cache是避免一些计算,因此索引将是计算的参数,如果已经存在,它将直接映射到结果。

现在,您实际上可能需要第二个索引,以从缓存中删除对象,但这不是强制性的。当然还有其他可用的策略。

如果您确实希望在应用程序中的其他任何地方不使用对象时立即将其从缓存中删除,那么,您可以有效地使用二级索引。这里的想法是根据T*,而不是weak_ptr<T>,而是保留索引,因为否则你无法在相同的引用计数上weak_ptr<T>创建新的。shared_ptr

确切的结构取决于计算的参数是否难以在事后重新计算,如果是,一个简单的解决方案是:

template <typename K, typename V>
class Cache: boost::enable_shared_from_this<Cache>
{
  typedef std::map<K, boost::weak_ptr<V>> KeyValueMap;
  typedef std::map<V*, KeyValueMap::iterator> DeleterMap;

  struct Deleter {
    Deleter(boost::weak_ptr<Cache> c): _cache(c) {}

    void operator()(V* v) {
      boost::shared_ptr<Cache> cache = _cache.lock();
      if (cache.get() == 0) { delete v; return; }

      DeleterMap::iterator it = _cache.delmap.find(v);
      _cache.key2val.erase(it->second);
      _delmap.erase(it);
      delete v;
    }

    boost::weak_ptr<Cache> _cache;
  }; // Deleter

public:
  size_t size() const { return _key2val.size(); }

  boost::shared_ptr<V> get(K const& k) const {
    KeyValueMap::const_iterator it = _key2val.find(k);
    if (it != _key2val.end()) { return boost::shared_ptr<V>(it->second); }

    // need to create it
    boost::shared_ptr<V> ptr(new_value(k),
        Deleter(boost::shared_from_this()));

    KeyValueMap::iterator kv = _key2val.insert(std::make_pair(k, ptr)).first;
    _delmap.insert(std::make_pair(ptr.get(), kv));

    return ptr;
  }


private:
  mutable KeyValueMap _key2val;
  mutable DeleterMap _delmap;
};
Run Code Online (Sandbox Code Playgroud)

请注意特别困难的一点:指针可能比 更长寿Cache,所以我们在这里需要一些技巧......

供您参考,虽然这似乎可行,但我对这段代码一点信心都没有:未经测试,未经证实,bla,bla;)