スマートポインタの効能
スマートポインタとは?
C++のポインタは、 ポリモルフィズム(多態性)などを使うには必須の機能ですが、 とかくバグの原因になりがちです。
newしたらdeleteするというのを忘れちゃいけないのから始まって、 コピーをしたらどうなるの?とか、 このポインタをあっちでもこっちでも使い回したい時はどうなるの?とかになると もうお手上げくんです。
こういったポインタの難しい部分を隠してくれるのがスマートポインタ。C++標準ではauto_ptrというのが用意されており、 auto_ptr型変数にnewしたポインタを管理させておくと、 変数がスコープをはずれる時に自動的にポインタをdeleteするという機能があります。
でも、コピーすると2つのauto_ptrにポインタが格納されちゃって、 どっちかがスコープをはずれるとdeleteされてしまって両方使えなくなるという問題もあって、 使いどころが難しい(実質関数ローカルな作業変数くらいに限られてしまう)ものです。
これを改善すべく、ポインタがコピーされた回数(参照カウントという)を数えておいて、 スマートポインタ変数が消えるたびに参照カウントを減らし、 参照カウントが0になったらdeleteを実行するというアプローチがあります。
すでに数々の実装があるのは知っていたのですが、 検索しててよさそうだと思ったのがここにあるshared_ptr。C++業界では有名なεπιστημη氏を始めいろいろなところでに紹介されていました。
使ってみるとなるほど良い感じです。とりあえず、あるスプライトクラスpatternがあるときに、
boost::shared_ptr<pattern> ppat = new pattern(...);
としておけば、いくらコピーしようと使われなくなった時点で (正確にはどのshared_ptrにも参照されなくなった時点で)メモリがdeleteされるのです。
アニメーションに使う
そこで最近の応用例。今つくっているゲームプロジェクトJet馬では たくさんスプライトが必要なのですが、 この管理に使ってます。
しかもスプライトはアニメーションするのですが、 アニメーションのスピードを調整するために何フレームかの間同じ画像を表示する必要がありますが、 いちいち(a)この画像は何フレーム表示して、次の画像は・・・なんてやるよりも、 (b)同じ絵が続くときは同じ画像を連続して登録するほうが簡単です。ぱらぱら漫画にたとえれば、 (a)が「このページは何秒見てね」というやりかたで、 (b)は「同じ絵を複数のページに書く」ということになります。
でも同じ絵を登録するために別のメモリを割り当てるのは明らかに非効率的です。そこでポインタをコピーするのですが、スマートポインタに包んで行います。 何フレームコピーされてようと、 全部のスマートポインタを削除すれば(しかもスマートポインタは自動変数だから明示的に行わなくて良い)、 とにかく安全にメモリは解放されます。
また、複数のアニメーションで同じ画像を利用する時にはもっとありがたいことが分かるでしょう。
もっと派手につかう
さて、アニメーションを作るためには元となるフレーム画像を用意しなければなりません。
あるビットマップを32x32に切り分けてvectorに登録します。
std::vector<boost::shared_ptr<pattern> > v;
load_patterns("あるビットマップ", v); // 切り分けて登録する関数
そして、アニメーションとして別のvectorに登録します。
std::vector<boost::shared_ptr<pattern> > a;
a.push_back(v[0]);
a.push_back(v[0]);
a.push_back(v[1]);
a.push_back(v[1]);
a.push_back(v[3]);
a.push_back(v[3]); // 0,1,3の画像が各2フレームずつ表示される
このとき、元の\var{v}に100個の画像が登録されていたとしても、\var{a}に登録されなかった0,1,3以外の全ての画像は \var{v}の消滅とともに消え去ってくれてしまいます。
Jet馬では、アニメーションのフレームになる画像の番号を自由にしたいのでvectorではなくmapを使っており、 もっとわけが分かりません。でも、元の画像はとりあえず無頓着に読み込んでおいて、 アニメーションとして使うものだけ登録し、 登録されなかった画像は自動的にいなくなってくれています。
どの画像は登録されたから削除できない・・・とか、 どの画像はどことどこに登録したから・・・とか、 もう考える必要はないのです!!やったぁ!
ところで・・・
今日の話題と全然関係はないのですが、 我がWebサイト「munepi.com」のログを見ると、MailEraserやパーソナルな英辞郎が置いてあるページと、なぜかここのアクセスが多いんです。
前者は分かるが、後者はなぜ・・・。