はじめに++あるクラスから派生したクラスで、基底クラスのメソッドをオーバーライドしたとする。この時、派生クラスがコンパイル時にわかっているときに、コンパイラはそれを認識して最適化できるか試してみた。++使うコンパイラは以下の通り。20171018++ただし、インテルコンパイラについては最後でちょっと触れるだけにする。静的な宣言++こんなコードを考える。h.func();+}+```++関数`func`は常に1を返す関数であるが、それをコンパイラが認識できるか試す。test1.cpp+```++などとしてアセンブリを見て、`func`が即値を返せるか調べる。++まずg++の場合。ret+```++clang++の場合(不要な情報を削ってある)。retq+```++うん、どちらも即値で返せていますね。このあたりは認識して欲しい気がする。h->func();+}+```++g++の場合。ret+```++律儀にnewを呼んだりしているけど、即値で返していますね。++clang++の場合。retq+```++なんとclang++の場合はnewも不要と判断してしまう。スマートポインタの場合++スマートポインタを使ってみよう。h->func();+}+```++g++の場合。ret+```++律儀にnewとdeleteを呼んでいるけど、即値で返している。++clang++の場合。retq+```++先程と同様、即値で返す上にnewやdeleteも呼ばない。オーバーライドした場合++さて、オーバーライドがからむ場合。基底関数のメソッドを派生クラスでオーバーライドするのだが、誰がオーバーライドしたかコンパイル時にわかる場合。20の三通りの可能性があるが、newされているのは`Hoge1()`なので返り値は10になることがわかる。それをコンパイラが見抜けるか。ret+```++おおー、ちゃんと即値で返していますね。++clang++の場合。retq+```++clang++の場合はこれまで同様、即値で返している上に不要なnewとdeleteも呼ばない。初期化と条件分岐がからむ場合++これが本命。条件によって異なる派生クラスが作られるのだが、どの派生クラスが作られるかはコンパイル時にわかる、というケース。func(-1.0);+}+```++ファクトリメソッド・パターンが絡んでいると思えば良い。`func`の引数の正負で`Hoge1`か`Hoge2`のどちらが実体化されるかが決まるが、`func2`では負の数を入れて呼んでいるため、`func`では`Hoge1`が作られることが確定。すると`h->func()`が10を返すことが確定するため、`func2`の返り値も10となる。ここまでコンパイラが見抜けるか、という話。ret+```++g++はここで力尽きた。`Hoge1`が作られるところまではわかったが、`Hoge1::func`のインライン展開まではしなかった。++で、clang++の場合。retq+```++最後まで最適化が通り、即値で返してくる。まとめ++ある関数が派生クラスでオーバーライドされているが、どのクラスでオーバーライドしているかがコンパイル時にわかる、という条件でどこまで最適化されるか調べた。clang++は最後まで最適化が通り、かつ不要なnewとdeleteも削除してくれる。これはわりと大したもんだと思う。g++は最後まで仮想関数テーブルはひかなかったが、作成したクラスのメソッドのインライン展開はしなくなったため、ケース5で即値で返せなくなった。ちなみにインテルコンパイラはケース3までは即値で返せたが、ケース4から真面目に仮想関数テーブルをひくようになった。++ファクトリメソッド・パターンで、ある変数の値に応じて異なるクラスの実体が作られるようにしたいのだが、その変数はコンパイル時に決定している、という状況があって、そこで軽い関数を頻繁に呼ぶのでちょっと性能が気になって調べたのだが、clang++なら(少なくとも今回程度の複雑さなら)オーバーライドなしで生関数呼んだ場合と同じ性能が出せるみたいですね。