boost::shared_ptr と boost::weak_ptr を使って異種型混合キャッシュ

boost::weak_ptr のメジャーな使い方にキャッシュがあるけれど,単にキャッシュで使うような例示コードはどっかに転がっている気がする (でもさっきぐーぐるせんせにお聞きしたら日本語では転がってないみたいだけど) ので,もう1段 boost::shared_ptr< void > も使って,異なる型のオブジェクトのキャッシュ管理を単一のマネージャでやらせるっぽいアレ以外の何か with 任意.

#include <string>
#include <deque>
#include <map>
#include <iostream>

#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_smallint.hpp>
#include <boost/random/variate_generator.hpp>

class CacheManager
{
public:
  explicit CacheManager( std::size_t sz )
    : cache_sz_( sz ),
      heterotype_cache_()
  {}

  void addCache( boost::shared_ptr< void > const &p )
  {
    heterotype_cache_.push_front( p );
    if( heterotype_cache_.size() > cache_sz_ ){
      heterotype_cache_.pop_back();
    }
  }

private:
  std::size_t cache_sz_;
  std::deque< boost::shared_ptr< void > > heterotype_cache_;
}; // class CacheManager

char *g_str[6] = {"道化","幽霊","愚者","天使","巡礼者","水妖"};

boost::shared_ptr< std::string > doHeavyProcess1( int i )
{
  return boost::shared_ptr< std::string >( new std::string( g_str[i] ) );
}

boost::shared_ptr< int > doHeavyProcess2( std::string const &str )
{
  std::ptrdiff_t i = std::find( g_str, g_str + 6, str ) - g_str;
  return boost::shared_ptr< int >( new int( i ) );
}

int main()
{
  typedef boost::mt19937 RNG;
  RNG rng;
  typedef boost::uniform_smallint< int > DIST;
  DIST dist( 0, 5 );
  boost::variate_generator< RNG, DIST > rnd( rng, dist );

  CacheManager manager( 2 );
  std::map< int, boost::weak_ptr< std::string > > string_cache_map;
  std::map< std::string, boost::weak_ptr< int > > int_cache_map;

  for( int t = 0; t < 20; ++t ){
    int i = rnd();
    boost::shared_ptr< std::string > p;
    if( p = string_cache_map[i].lock() ){
      std::cout << i << " -> " << *p << " (cache hit)" << std::endl;
    }
    else{
      p = doHeavyProcess1( i );
      manager.addCache( p );
      string_cache_map[i] = p;
      std::cout << i << " -> " << *p << " (cache not hit)" << std::endl;
    }

    if( boost::shared_ptr< int > q = int_cache_map[*p].lock() ){
      std::cout << *p << " -> " << *q << " (cache hit)" << std::endl;
    }
    else{
      q = doHeavyProcess2( *p );
      manager.addCache( q );
      int_cache_map[*p] = q;
      std::cout << *p << " -> " << *q << " (cache not hit)" << std::endl;
    }
    std::cout << std::endl;
  }
}

上のコードの焦点は,異なる型 (上のコードでは int と std::string) のオブジェクトのキャッシュ管理を, boost::shared_ptr< void > を使って単一のキャッシュマネージャに統合しているところであって,ヒットしたら deque の front に持っていくとか,キャッシュオブジェクトの数じゃなくてサイズでキャッシュの消去をトリガーするとか, manager を独立のスレッドで動かすとか,そこら辺のことに関しては全くやってないので適宜,勝手に読み替えてねー(^o^)ノ.
http://d.hatena.ne.jp/Cryolite/20060108 の boost::shared_ptr< void > の使い方で「実際の型で使うにはダウンキャストしないといけない」としか書かなかったせいで,読んだ人が「boost::shared_ptr< void > はダウンキャストする以外に使い道がない」って誤った結論を導くことになったら困るから, boost::shared_ptr< void > の (型安全な) 使い方の1例としてこれを書こう書こうと思いつつウダウダしてたっていうのは内緒だよぉ?要するに void だから具体的な型の情報は全く持っていないけれど, C++ のあらゆるオブジェクトに共通する「デストラクタの発動」だけは void な型情報でも全く問題ないよ,ってゆ〜.