14

私の初心者の評判のため、このスレッドには返信できません。具体的には、受け入れられた回答です。

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 参照から 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何らかの計算を回避することです。したがって、インデックスは計算のパラメーターになり、既に存在する場合は結果に直接マップされます。

キャッシュからオブジェクトを削除するために、実際には 2 つ目のインデックスが必要になる場合がありますが、これは必須ではありません。もちろん、他の戦略も利用できます。

オブジェクトがアプリケーション内で使用されなくなったらすぐにキャッシュからオブジェクトを削除したい場合は、効果的にセカンダリ インデックスを使用できます。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;
};

特別な困難に注意してください: ポインターは よりも長生きする可能性があるCacheため、ここでいくつかのトリックが必要です...

参考までに、実行可能のように見えますが、私はこのコードにまったく自信がありません: テストされていない、証明されていない、bla、bla ;)

于 2011-12-09T17:49:45.453 に答える