0

私のプログラムは(REST APIから)多くのオブジェクトを作成および削除します。これらのオブジェクトは、複数の場所から参照されます。「メモリキャッシュ」を用意し、参照カウントを使用してオブジェクトの存続期間を管理して、オブジェクトが使用されなくなったときに解放できるようにしたいと考えています。

すべてのオブジェクトは基本クラスから継承しますRessource

ほとんどCachestd::map<_key_, std::shared_ptr<Ressource> >

それから私は困惑しています、 refカウントがCacheいつデクリメントされるかをどうやって知ることができますか?Ressourceすなわち。std::shared_ptr destructorまたはへの呼び出しoperator=

1 / std :: mapを繰り返し処理して、各ref.count()を確認したくありません。

2 / std :: shared_ptrを再利用して、カスタムフックを実装できますか?

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

3 /独自のrefcountクラスを実装する必要がありますか?元。https://stackoverflow.com/a/4910158/1058117

ありがとう!

4

4 に答える 4

1

map<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

The problem is, that in your scenario the pool is going to keep every reference alive. Here is a solution that removes resources from a pool with a reference count of one. The problem is, when to prune the pool. This solution will prune on every call to get. This way scenarios like "release-and-acquire-again" will be fast.

#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 に答える
1

make shared_ptr not use deleteは、共有ポインターにカスタムの削除関数を提供する方法を示しています。

追加と削除を参照するための顧客関数が必要な場合は、侵入ポインターを使用することもできます。

于 2013-01-26T12:52:37.900 に答える
0

プールが必要なキャッシュは必要ありません。具体的には、オブジェクト プールです。あなたの主な問題は、参照カウントを実装する方法ではありません.shared_ptrはすでにそれを行っています。リソースが不要になったら、キャッシュから削除するだけです。主な問題は、一定の割り当て/削除によるメモリの断片化と、グローバル メモリ アロケータでの競合による速度低下です。答えについては、スレッド固有のメモリ プールの実装を参照してください。

于 2013-01-26T12:54:13.247 に答える