C++ 実行速度アップ術

Last-modified: 2015-09-24 (木) 12:39:47

まず初めに。

まず初めに。

この文書の「読み方に対する」注意事項

  • ここでいう「パフォーマンス」は、特に明記しない限り「速度的」なものです。
  • アセンブリは使いません。あくまでC++のみの話です。ヒット率なんて知りません。

この文書の「内容に対する」注意事項

  • あくまでも「指針」です。
  • 基本的にパフォーマンスは上がりますが、環境によっては下がってしまいます。
  • パフォーマンスが下がる恐れもあるので、必ず自身の手でパフォーマンスを確認してください。

その他の注意事項。

次のことを自身に問いかけましょう。

  1. わずかなパフォーマンスのために、コードの簡潔さを犠牲にしない。→読み易さ、わかりやすさの方がパフォーマンスよりも重要になることがあります。
  2. パフォーマンスのチューニングは、必要になったときに行う。→時期尚早なチューニングは、無駄になることが多いです。が、チューニングを行って損をするのが自分だけであるなら、やっても良いとは思います。
  3. 優先すべきは、パフォーマンスではなく、使い手の意志です。→お客さんが求めている本質は、パフォーマンスではなく「使い勝手」かもしれません。

C++でなくてもできる、パフォーマンスアップ術

C++を詳しく知らなくても、できるパフォーマンスアップ術(?)をまとめます。

「限定的」が高速。

たとえば、2つの「std::string」オブジェクトを入れ替える処理を行う場合、次の3つの方法があるかと思います。

  • (a) 自前でやる  (パフォーマンス:低)
    string a, b;
    string tmp = a;
    a = b;
    b = tmp;
  • (b) std::swap()を使う  (パフォーマンス:中)
    string a, b;
    swap(a, b);
  • (c) std::string::swap()を使う  (パフォーマンス:高)
    string a, b;
    a.swap(b);

これら3つの手法のうち、(a)は無駄なコピーも起こりますし、無駄な一時オブジェクトも作られてしまいます。その一方で、(c)は、string自体が持つswap()を利用することで、stringクラス内部でしか扱えない変数を扱えたりできるので、高速性が期待できます。また、(b)は、stringに特殊化されたstd::swap()があれば、やはり高速に実行できることが期待できます。
気持ち的には、(c)、(b)、(a)の順でパフォーマンスが期待できます(stringの場合、4~5倍速くなります)。
(b)は、STLライブラリを使用する場合に限り、(c)と同等の動作を期待できます。
しかしSTL以外のライブラリであれば、(b)は(a)と同等程度のパフォーマンスしか期待できません。
逆に、ライブラリ製作者は「swap()」関数くらい実装したいものです。

というわけで、関数であれ何であれ、より限定的なものの方がパフォーマンスに期待が持てます。
stringの交換プログラムサンプル

C++の基本的なパフォーマンスアップ術

以下に挙げる事項は、初めからやっておいても損は無いパフォーマンスアップ術(?)です。
特にコンパイラやライブラリの実装、実行環境に左右されることない方法だと思います。

inline関数にする。

・・・高速化したり、しなかったり・・・。

constにする。

演算子のオーバーロードを意識する。

○演算子のオーバーロード
C++ では、実は演算子さえもオーバーロードできます。 通常なら +演算子は値を加算するものですが、これをオーバーロードして減算させることもできます。

auto を使う。

C++11 で追加された「auto」キーワードは、オート変数の型として使用できます。
こうすと、オート変数の型がコンパイル時に類推され、「最もパフォーマンスの良い型」として扱ってくれます。
もちろん、コピーを許さないことを明示したい場合などに、const や参照の&をつけても構いませんが、
何より、無駄な変換処理を発生させないという利点があります。
たとえば、明示的に型を指定した場合、その型の変数で、別の型の値を受けた場合に、operator=や、引数付きのコンストラクタが動作して、無駄なコピーや変換などが行われている可能性があります。
これは、ソースコードを見るだけだと、わかりにくい動作になってしまいます。
最終的にボトルネックを探そうとプロファイラを通せばわかることかもしれませんが、無駄な時間をすごさないためにも、あと初心者、中級者の間違いを減らすためにも、autoを使って、初めから無駄なパフォーマンス低下を防いだほうが得策です。

C++最後のパフォーマンスアップ術

基本的に、コンパイラやライブラリの実装、実行環境に左右されるようなパフォーマンスアップ術(?)です。
一度くらいは実際に検証用のコードを書いて、パフォーマンスを調べることが望まれます。
ほとんどの場合、アセンブリを書いたり、システムに依存しまくりの方法をやるほうが、作業的には楽だと思います。

参考