さくらんぼのlambda日記

lambdaちっくなことからゲーム開発までいろいろ書きます。

boostのmulti_indexが便利な件について

割と最近真面目に使いだしたboostライブラリ。
色々と便利な機能が満載すぎて正直素敵すぎます。

個人的に便利だと感じたのは、multi_indexですね。
これはコンテナに複数のインデックスを張ることを可能にするものです。

どういう状況で便利なの?

どういう時に便利かを説明するために、ここでは
ゲームのキャラクタを表現するCharactorクラスを考えてみます。
そして、このCharactorクラスを大量に管理、更新する状況を考えて見ましょう。

まずは、Charactorクラスの例です。

struct Charactor {
  int         id;
  int         x,y;
  std::string name;
  
  Charactor(int x,int y,const std::string& name):x(x),y(y),name(name){}
  
  // 標準の順序は、idの大きさで決定する
  bool operator<(const Charactor& e) const {
    return id < e.id;
  }
  
  // デバッグ用の出力関数
  void print() const {
    std::cout << "[name:" << this->name 
              << " , id:"  << this->id 
              << " , x:"  << this->x 
              << " , y:"  << this->y 
              << "]"      << std::endl;
  }
  
};

このCharactorクラスを管理しようとした場合、手軽で強力な手段としてSTLのコンテナ
という手段があります。

Charactorクラスのvectorなりlistでゲーム中のキャラクタを管理すれば、
毎フレームこれらのvector、listの各要素を更新することで、ゲームのキャラクタの動作を実現できます
(もちろん抽象クラスにしてポリモルフィズムを活用してね!)。


こういった場合、vector、listだと、以下の様なコードで
毎フレーム、各キャラを更新するのが普通だと思います。

vector<Charactor> charactor_array(MAX_NUM); 
// キャラクタを更新!!
for_each(charactor_array.begin(), charactor_array.end(), mem_fun_ref(&Charactor::Update));

先の手法の問題点!

先のfor_eachの構造で、ゲームのキャラクタの一括管理という目的は達成できます。
しかし、先の構造のまま実際にゲームを開発しようとしてもさまざまな問題が発生します。
特に描画や特定の範囲のオブジェクトがほしいといった場合に困ったことが発生しやすいです。

例えばゲームの場合ですと

  • idの500番以上は敵専用で扱いが違う
  • キャラクタを描画するときはY軸の順番に描画

といった状況があります。


こういった状況の場合、vectorやlistのsort()と比較関数をそれぞれ定義すれば対応することも可能ですが
欠点もあります。

  • 比較関数の名前を考えなければならない
  • いつ、どのソートをしたのかをプログラマ自身が把握しておかなければならない
  • vectorやlistの要素の中身(Charactorクラスのインスタンス)に変更があった場合にプログラマが明示的に再ソートする必要がある

そこでboost::multi_indexですよ!

この上記の欠点を解決してくれるのがmulti_indexです。
特徴としては、

  • 1つのコンテナに対し複数のインデックスを作成し、そのインデックスでアクセスが可能
  • コンテナの要素に変更があった場合、すべてのインデックスが自動的に更新される

があげられます。



multi_indexを利用することで、プログラマ

  • 関数を利用して並び替えないため、比較関数名を考える必要が無い
  • 自動でインデックスが更新されるため、いちいち再ソートを意識しなくて良い
  • 要素を変更しても再ソートの必要が無い

という恩恵にあずかることが出来ます。

じゃあ、早くコード見せてよ

すいません><
ここまで書いておいて時間が足りませんでした><
次回、コード付きで解説しますね!