VC10 と C++0x その1:Placement Insert

C++0x の勉強も兼ねてしばらくこのネタを引っ張る予定なのでその1。
週一個くらいは C++0x の機能をざっくり補完していきたい。


ゲームを作っていると、敵やらエフェクトやらのデータをリスト(コンテナ)に格納して順次処理したり、管理したくなる場面が多くでてくる。
で、前回(ARCANUM ECHO)の時は、自前のリストを作成して色々と処理をしていたのだけど、やっぱり機能的に不十分な面(とかバグとか)が多々あったりする。
そんな訳で、やっぱ std コンテナ使いたいよねー、という事でちょっくら調査してみた。


ゲームにおいて std コンテナがあまり用いられていない(ような気がする)一番の原因は、コンテナにクラスインスタンスを登録(push_back とか insert とか)する時に、コンストラクタが呼び出されてしまう点だと思う。
コードにすると↓な感じ。

class Hoge {
  Hoge(int babaa);
};

Hoge tmpHoge(17); // ここで一度コンストラクタが呼ばれる
std::vector ac;
ac.push_back(tmpHoge); // 登録時にコピーが発生し、もう一度コンストラクタが呼ばれる
ac.push_back(Hoge(17)); // コンストラクタが二度呼ばれる

これは、特に敵データのような巨大なクラスをコンテナに格納する場合やエフェクトや敵弾等のようにコンテナへの登録回数が多い場合には無視できないコストとなり、処理速度を最重視するゲームにとってマジフザケンナ仕様と言える。
※メモリ領域のリサイズとそれに伴うコピーコンストラクタの呼び出しについては reserve を使えば問題ない
コンストラクタで何も行わず、コンテナに格納後初期化処理を行うクラスを用いる等の回避方法は無い事もないけど、その場合は何の為のコンストラクタやねん、となるし、何よりコードが分かり辛い。

class Hoge {
  Hoge();
  init(int babaa);
};

Hoge tmpHoge(); // ここで一度コンストラクタが呼ばれるが処理を行わないので軽い
std::vector ac;
ac.push_back(tmpHoge); // 登録時にコピーが発生し、もう一度コンストラクタが呼ばれる
ac.back().init(17); // 変数初期化処理

んで、凄く今更感溢れてる(最近になって C++0X 仕様を見始めた駄目な子)けど、C++0x ではこの問題を解消する機能、Placement Insert が追加されたらしい。
Placement Insert については、
C++0x コンストラクタの引数をとる push_back(Faith and Brave - C++で遊ぼう)
にて詳しく解説されております。
※Placement Insert については explicit の問題とかいろいろあるので注
ざっくり説明すると、push_back にクラスのコンストラクタ引数を渡す事ができるようになり、コンストラクタ呼び出しも 1 度で済む、というもの。
参考コード↓

class Hoge {
  Hoge(int babaa);
};

std::vector ac;
ac.push_back(17); // 17 を引数にコンストラクタが一度だけ呼ばれる

これは素晴らしい。なんで今までなかったのか分からないくらい(可変長引数テンプレートの問題だから中々難しい所なんだろうけど)。
と言う訳で、嬉々として VS2010 評価版をインストールして Placement Insert を試したらコンパイルエラー。
なんと、VC10 は Placement Insert(というか可変長引数テンプレート) に対応していないのであった。なむなむ。




……一応対策をば。
1. 自前でリストクラスを作成してデータ管理する
必要機能絞れば実行速度でも std に負けないものが作れる。きっと。
と思ったけど、move を駆使している std に勝てる気はしねー。


2. 途中で出てきた空のコンストラクタを用いる実装を行う
init の際に色々工夫すればそこそこの速度は期待できる。
コードが冗長になるけど、そこは諦めるしかなさげ?


将来的に VC10 が可変長引数テンプレートに対応した場合(現状そんな予定はないっぽいけど)に、コードの移植性が高いのはどっちかを考えると、2の方が良い……のかなぁ。
※※Placement Insert である emplace、emplace_back が関数として用意されている(挙動は単に push_back するだけの詐欺関数ですが!)ので、対応するつもりなんだと信じたい
しばらく悩みたいと思いまする。