last update: 2013/09/03

2005/03/11

Effective STL

実質200ページぐらいの薄っぺらい本です。

ってことで、正月に買ったデータ構造とアルゴリズムの本より読む量が少ないぐらいなので、あの本は列車で1時間ぐらいで読破したことを考えれば、まぁ読むだけなら1時間ぐらいで読めるだろうとタカをくくって帯広行きの列車で最初1時間半ぐらい寝て、そのあと目が覚めたのでずっと読んでいましたが……おいおいおいおい、1時間ちょっとで40ページぐらいしか読めてないって一体…。

ってことで、すげー難しいです、これ。いや、逆に単に目を通すだけなら普通にさくさく読めますが、なまじSTLをバリバリつかってるばっかりにかなり本気出して読んでるのでコードの意味とか、方法論とか、そういう本文中には書いてない背景的なことまで読もうという感じになって全然読み進められない感じだったんですが、とりあえず5時間ぐらいかけてなんとか読破。

まぁ内容的にはいたって単純明快です。STLに用意されてるアルゴリズムでできることは自分でループまわしたりしないでそれ使えってことがまずひとつ、operator==でテストしてるときの意味的な等号判定は等値と等価2つあるよ、Cスタイルの配列とかメモリ確保よりはSTLのコンテナがいいよ、とかまぁそんな感じでした(まだまだあるけどね)。

とりあえずひとつ目からうろこが落ちたのは関数ポインタと関数オブジェクト。第46項の「アルゴリズムのパラメータとしての関数の代わりに関数オブジェクトの利用を考えよう」ってやつですね。たとえばstd::sortとかは第3引数に比較関数を指定することができるわけですが、そこに関数(ポインタ)を指定するか、それとも関数オブジェクトを指定するかって話で、ここでは関数オブジェクトの使用を勧めてるわけです。まぁ、STLだし、オレだったらたしかになんかテンプレートで抽象化した関数オブジェクトとか渡してるけど、ここで関数ポインタを渡すと、なんとパフォーマンスが落ちるんですってよ、奥さん。

どういうことかっていうと、関数オブジェクトでoperator()がインライン関数になっていればstd::sortが展開されるときに関数オブジェクトのoperator()はインラインなのでその場でインライン展開されるわけですが、ここで関数ポインタを指定するとどうなるかというと、関数ポインタはあくまでも関数ポインタなので(つまりポインタを用いて関数を呼び出すことしかできない)、関数をインライン展開することはできないんですね。これにより、関数ポインタのさす関数がinlineになっていても、std::sortは関数ポインタに対する関数呼び出しを生成するので、インラインとかそういうのは関係なく関数呼び出しが発生する、よって関数オブジェクトを利用してoperator()をインライン展開したケースよりもパフォーマンスが落ちるんだそうで。たしかに納得できる説明ですね。

ちなみにEffective STLでは続けて「関数ポインタもコンパイラが最適化の過程で関数ポインタの示している関数がインラインだったらそれをインライン展開するような最適化をすればいいじゃないか」というように読めるようなことも書いてありますが、やっぱ関数ポインタとはいえポインタであることを考えるとポインタの差すアドレスが変えられてしまうことを考えればインライン展開は無理ですよねー。具体的に関数オブジェクトならばコンパイラがコンパイルの時点で関数呼び出しを解決するので唯一の関数が決定しますけど、関数ポインタであればあくまでもポインタに過ぎないので実行時にポインタの指し示す先を変えることができうるので、そのような状況も想定すると関数ポインタの差す先をコンパイル時にインライン展開はできませんね。

とまぁそんな感じでした。とりあえず初心者は読んでもわけわかんないと思うし、買うだけ無駄だと思いますが、STLを使いこなしていると自負している人は試しに読んでみるといいと思います。いかにそれが思い上がりかとよくわかるっていうか、まぁ正直私もまだまだSTLのアルゴリズム部分は使いこなせてないなぁって思いましたねー。

comments powered by Disqus