愚者3人

土曜日は部室に来た時点で終電が無くなっていたと主張する(爆笑)ちょーA氏と、ホイホイついてきちゃったIくんと、なんか3人が家に着いた後「宿泊できますか」という完全に頭の悪いメールを送ってきたどるさんが来ました。


どるさんはEffective C++を熱心に読んでいました。この超良言語(爆笑)を紹介できたことを嬉しく思います。文法をとりあえず一通りだいたい理解したくらいが対象の基本事項集で、C++で何かやろうと思うなら必読の超良書です。まあ、ただ、ゆえに、世紀末プログラミングについて大量のページを割いていたりはしません。Modern C++ Designとかやってればいいんでねーの。

Effective C++ 原著第3版 (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES)

Effective C++ 原著第3版 (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES)


道中、ゴミが溜まってどうしようもなくなるまでどうにかしないでしょとか言われて、そうかガーベジコレクションかと思ったが、分かる人がいなかった。残念。GCは重いからなあ。必要にかられるまでは絞るのが基本。


毎度おなじみ「やっぱ役満でしょ」アカウントによるニコ生実況が行われました。かなり調子は悪かったのですが、最終的には前回の通り。直撃を狙える国士の一発Fatal KOでその場で終わらせる(ツモ損の8000・16000(24000)では逆転される可能性が往々にあり)という理想形を達成しました(まあオーラスだったんだけどね)。前回の日記に牌譜へのリンクを追加しておきました。


日曜日は日吉に買い物に行って、早く帰って約束したゲーム制作講座(笑)の放送でもするかと思ったけどメッセを開いたらそれっぽい人が全くいなかったので賢者しました。なお、次の土日はICPCがあるのでできません^^。平日のどこかで賢者して月曜までの実験レポート書かないと…。水曜PC持参まであるな…。
PCのゲームパッドをもういい加減PS2コンに移行しようかと思ってコンバータを買ったものの、肝心の新品のPS2コンが手に入らず残念拳。


標準仕様に入っていなかった(後述)からか、意外と知ってる人が少ない気がするスマートポインタについて。ずっと世紀末(も多く含まれる)ライブラリboostを入れる必要があって、標準仕様に入っていない(auto_ptrってゴミはあるんだけど…)のが欠陥とも言われていたものですが、C++0xでついにshared_ptrやその仲間たちが標準ライブラリ入りしました。移行期はstd::tr1名前空間に入っていたこともありましたが、VC2010ではstdから使えます。unique_ptr(旧boost::scoped_ptr)も使えるようですが、なぜかVCのドキュメントに見当たりません。
スマートポインタはデストラクタによって変数の有効範囲を外れたときに自動的にdeleteしてくれるクラスです。std::shared_ptr(#include )は参照カウントを使ったスマートポインタです。2つ以上の生ポインタと一緒にいくつのshared_ptrから参照されているのかという数が保存されており、コピーコンストラクタや代入でインクリメント、デストラクタでデクリメント(0になったらポインタをdelete)することで、生ポインタを一度shared_ptrで包んだら好き放題いろいろなところでコピーしてもすべての参照が無くなったところで解放されるという優れものです。実質的にほぼJavaガーベジコレクションに頼っているのと同じ感じでコードが書けます。(一応循環参照が永パになるという(???)弱点はあります。一緒にweak_ptrが導入されているのでそちらで。)

while (...) {
  /* MyClass *p = new MyClass; */
  std::shared_ptr<MyClass> p(new MyClass);
  ...
  if (...) {
    // 手動deleteの場合、whileループの最後以外にこういう
    // break/continue/return/throwなどの前にもdeleteを
    // 書かなければならない
    // でもデストラクタの利用によりスマポなら大丈夫
    /* delete p; */
    break;
  }
  ...
  // pがスコープから外れるここで自動delete
  /* delete p; */
}

// クラスをnewして返すとかdeleteの義務を呼び出し元に
// 押しつけることになってやりたくなかったけど
// スマートポインタに包めばやりたい放題
std::shared_ptr<MyClass> getMyInstance() {
  return std::shared_ptr<MyClass> p(new MyClass);
}

// 引数のスマートポインタをメンバ変数にコピーしても
// 全然構わないんで
// SomeClassのインスタンスのデストラクト時にスマートポインタの
// デストラクタで参照カウントが減らされてそれで0になったのなら
// deleteされるんで
// std::vectorとかのコンテナに入れたりしても全然構わないんで
void SomeClass::func(std::shared_ptr<MyClass> p) {
  m_p = p;
  // std::vector<std::shared_ptr<MyClass>> m_vec;
  // >>問題って解決されたんだっけ
  m_vec.push_back(p);
}

複数のポインタから同時に参照されないことを前提・保証した、ちょっとオーバーヘッドの少なそうなunique_ptrもありますが、T *をshared_ptrにひたすら機械的に書き換えるだけで全く問題ない説まであるので試してみてはいかがでしょうか。
ポインタのdeleteに限らず、後始末の義務が残る問題(returnやthrowの前に忘れるバグ問題)はデストラクタで解決できるんですね。ミューテックス(一般用語、…いや、一般的な技術用語)のロック解放とか。
一般的なC++パターン:
なんでみんなこうしないのかと思う→C++の本やコミュニティでやっぱりこちらの方がいいんだと思う→いつの間にか周りに人がいなくなる
あ、私はデストラクタとスマートポインタを使うためだけにC++使います^^。