14

由于我的菜鸟声誉,我无法回复此Thread,特别是已接受的答案:

我从未使用过 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
    );

这个解决方案的问题是

(1) 比较运算符必须为每个比较获取所有权(即从weak_ptr refs 创建shared_ptrs)

(2)当最后一个管理资源的shared_ptr被销毁时,weak_ptr并没有从缓存中擦除,而是在缓存中保留了一个过期的weak_ptr。

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

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

干杯,丹尼尔

4

2 回答 2

4

您想要实现的可能解决方案可能是

可以说T是你的对象,shared_ptr<T>是你的共享 ptr

  1. T*在您的缓存中只有常规。
  2. 为您的自定义删除器shared_ptr<T>
  3. 让您的自定义删除T*器在删除时从缓存中删除您的。

这样,缓存不会增加您的引用计数,shared_ptr<T>但会在引用计数达到 0 时收到通知。

struct Obj{};

struct Deleter
{
    std::set<Obj*>& mSet;
    Deleter( std::set<Obj*>& setIn  )
        : mSet(setIn) {}

    void operator()( Obj* pToDelete )
    {
        mSet.erase( pToDelete );
        delete pToDelete;
    }
};

int main ()
{

    std::set< Obj* > mySet;
    Deleter d(mySet);
    std::shared_ptr<Obj> obj1 = std::shared_ptr<Obj>( new Obj() , d );
    mySet.insert( obj1.get() );
    std::shared_ptr<Obj> obj2 = std::shared_ptr<Obj>( new Obj() , d );
    mySet.insert( obj2.get() );

    //Here set should have two elements
    obj1 = 0;
    //Here set will only have one element

    return 42;
}
于 2011-12-09T14:23:00.140 回答
2

问题是,Cache缓存的对象本身没有解决您的问题,否则它将毫无用处。

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

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

如果您真的想在应用程序中的其他任何地方没有使用对象时立即从缓存中删除它们,那么您可以有效地使用二级索引。虽然这里的想法是根据T*, not进行索引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;
};

请注意特别困难:指针可能比 . 长Cache,所以我们需要一些技巧......

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

于 2011-12-09T17:49:45.453 回答