例外がスローされない場合、例外をスローする可能性のあるコードは、例外をスローしない同様のコードと比較してパフォーマンスが低下しますか?
9 に答える
「通常の」(例外関連ではない) コードでオーバーヘッドなしで C++ 例外処理メカニズムを実装できることが実証されています。ただし、実際には、コンパイラは通常、より単純な実装に固執するため、通常、効率の悪い「通常の」コードになります。コンパイラは、潜在的な例外が関数階層を通過する可能性を考慮する必要があるため、例外がスローされた場合に適切なスタックの巻き戻しを有効にするために、いくつかの追加のハウスホールド操作を生成する必要があります。この余分な家庭用コードは、例外がスローされるかどうかに関係なく、コードの全体的な効率に影響します。
これはすべて QoI (実装の品質) の問題です。コンパイラ固有です。詳細については、コンパイラを確認してください。一部のコンパイラは、例外がまったく使用されていない場合に最も効率的なコードを生成できるようにするために、C++ 例外を有効/無効にするオプションを実際に提供しています。
場合によります; テーブルベースの実装(最新のg ++が使用し、Windowsのx64バイナリに使用される戦略)は、スローされない例外の処理オーバーヘッドがゼロです(メモリ使用量がわずかに多くなります)。関数ベースの例外処理(x86 Windowsが使用)では、スローされない例外の場合でも、パフォーマンスがわずかに低下します。
トライは安い、キャッチは安い、スローは高い。明らかに、try 内にラップされたコードを実行する少し余分な処理があります。
例外的なものには例外を使用してください。オーバーヘッドは問題になりません。
これはコンパイラによって異なります。一部のコンパイラ/ランタイムの組み合わせは、catch ハンドラーを使用してブロックへのエントリで追加の作業を行います。他の人は静的データ構造を構築し、すべての作業はすぐに行われます。どの場合でもエントリ コストは throw よりも低くなりますが、内部ループでの catch ブロックには注意が必要です。気になるコンパイラで時間コストを測定します。
コンパイラによって異なりますが、答えはほぼ確実に「はい」です。具体的には、スコープに自明でないデストラクタを持つオブジェクトが含まれている場合、例外でデストラクタを呼び出すために、そのオブジェクトをランタイムに登録する必要があります。例えば:
struct Thing
{
~Thing();
void Process();
};
for (int i = 0; i < 1000000; ++i)
{
Thing thing;
thing.Process();
}
これは、100 万の Thing を構築して処理するだけでなく、Process の呼び出しがスローされた場合に、各 Thing を登録および登録解除するための 100 万の関数呼び出しも生成します。
try
これに加えて、対応するcatch
ブロックが例外ハンドラーのスタックに追加またはスタックから削除されるため、ブロックに出入りするときに小さなオーバーヘッドがあります。
コンパイラは、例外がスローされたときにスタックを巻き込むコードを生成する必要があるため、舞台裏で追加のコードがいくつかあります。しかし、それがかなり多いかどうかは議論の余地があります。
変数がスコープ外になったときにデストラクタを自動的に呼び出すために生成されるコード
そして、すべての呼び出しの終了ステータスをチェックしてエラーを処理するために記述する必要があるコード。
コストがかかるのはエラーをキャッチすることです: try ... catch ステートメントと、例外がスローされてキャッチされたときに何が起こるか:
try ... catch が追加された各場所に関する情報を保持します (また、デストラクタの周囲や例外仕様で暗黙的に追加されます)。
単純なジャンプのように見えるもののために巻き戻すための多くのスタック (および呼び出すためのデストラクタ)、
catch() 句にスローされた一致する例外、
例外をコピーします。
C++ パフォーマンスに関するドラフト テクニカル レポートのセクション 5.4 は、例外のオーバーヘッドに完全に専念しています。
「例外がスローされない場合にゼロオーバーヘッドを実装できる」かどうかに関係なく、理論的な議論すべてに関係なく、現実には、-O2 最適化を使用しても特定のコンパイラ (g++ 4.4) では、内部に throw 句があるという事実だけです。タイトループ関数 (つまりcpu-bound ) は、関数を 10 倍から 100 倍遅くします。これが問題です。これは、スローが実際に実行されない場合です。
したがって、私の提案は、疫病のような C++ での標準的な例外処理を避けることです (あなたが私を間違っていると証明しない限り)。パフォーマンスが重要なアプリケーションでエラー処理を行いたい場合は、boost.context を使用します
例外処理を行うコードは、例外処理を行わないコードに比べて遅く、サイズも大きくなります。
例外が発生した場合、スタックの巻き戻しプロセス中にオブジェクトが破棄されるように簿記を行う必要があるためです。