読者です 読者をやめる 読者になる 読者になる

凹みTips

C++、JavaScript、Unity、ガジェット等の Tips について雑多に書いています。

Boost.Flyweightのお勉強

C++

はじめに

友達とゲームをつくろう! みたいな話が持ち上がってきたりしたので、取りあえずのところのツールとして使えるように、広く浅く Boost のお勉強をしていこうと思い立ちました。まずはリソース管理周りに使えそうな Boost.Flyweight から。

Boost.Flyweight?

Flyweightパターンを実装してくれてるようです。画像とかテクスチャのリソース管理に使えそうです。

key_value

リソースの管理方法として、d:id:nagoya313:20100310:1268201496 みたいな感じで使いたいなぁ、と思ったので自分でもお試しにコードを書いてみました。

(2011/10/24 リソースを共有していることが分かるように修正)

#include <iostream>
#include <string>
#include <vector>
#include <boost/flyweight.hpp>
#include <boost/flyweight/key_value.hpp>

using namespace std;
using namespace boost::flyweights;

class Image_
{
public:
  explicit Image_(const string &file_name)
    : file_name_(file_name) {}
  void draw() const {
    cout << this << " : " << file_name_ << endl;
  }
private:
  string file_name_;
};

typedef flyweight<key_value<string, Image_>> Image;

int main()
{
  vector<string> file_names = {"背景.png", "自機.png", "敵.png", "背景.png"};
  vector<Image>  imgs;

  for (const string &file_name : file_names) {
    imgs.push_back(Image(file_name));
  }

  for (auto img : imgs) {
    img.get().draw();
  }
}

コンパイル:

g++-4.6 flyweight_test.cpp -std=c++0x -lpthread

出力:

0x82e219c : 背景.png
0x82e21cc : 自機.png
0x82e21fc : 敵.png
0x82e219c : 背景.png

no_tracking

格納されてるオブジェクトの破棄のタイミングは Flyweight の2番目のテンプレート引数で指定できるようです。デフォルトでは参照カウントオプションである refcounted が選択されています。

Boost.Flyweight Documentation - Tutorial - Configuring Boost.Flyweight - 1.41.0

挙動を知るために、 d:id:faith_and_brave:20091020:1256027041 をお勉強に使わさせて頂きました。以下抜粋。

#include <iostream>
#include <boost/flyweight.hpp>
#include <boost/flyweight/key_value.hpp>
#include <boost/flyweight/no_tracking.hpp>
#include <boost/noncopyable.hpp>

using namespace boost::flyweights;

struct compute_fibonacci;

typedef flyweight<key_value<int, compute_fibonacci>, no_tracking> fibonacci;

struct compute_fibonacci : private boost::noncopyable {
    compute_fibonacci(int n)
        : result(n == 0 ? 0 :
                 n == 1 ? 1 : fibonacci(n-2).get() + fibonacci(n-1).get()) {}

    operator int() const { return result; }
    int result;
};

int main()
{
    for (int n = 0; n < 40; ++n)
        std::cout << "F(" << n << ")=" << fibonacci(n) << std::endl;
}

no_tracking を指定しないと、fibonacci(n) がforループ毎に破棄されてしまい、せっかく Boost.Flyweight を使った意味がありません。これを防ぐために no_tracking オプションを指定して破棄のタイミングをプログラムの終了時にさせています。たぶん。