web-dev-qa-db-ja.com

try-catchブロックはパフォーマンスを低下させますか

この リンク 状態、

例外をキャッチするには、コードの一部を例外検査下に置く必要があります。これは、コードのその部分をtryブロックで囲むことによって行われます。そのブロック内で例外的な状況が発生すると、例外がスローされ、制御が例外ハンドラーに転送されます。例外がスローされない場合、コードは正常に続行され、すべてのハンドラーは無視されます。

Tryブロックがあると、実行時に「検査」という余分なタスクが発生してパフォーマンスが低下するということですか?

33
bibbsey

TL; DR[〜#〜] no [〜#〜]、例外は通常、より高速ですon-例外パスエラーコード処理と比較。


さて、明白な発言はと比較して何ですか?

エラーを処理しないことに比べて、明らかにパフォーマンスが低下します。しかし、パフォーマンスは正確性の欠如に値しますか?私はそうではないと主張するので、ifステートメントでチェックされたエラーコードと比較して、あなたが意図したと仮定しましょう。

この場合、それは依存します。例外を実装するために使用される複数のメカニズムがあります。実際、それらはifステートメントに非常に近いメカニズムで実装できるため、同じコスト(またはわずかに高い)になります。

ただし、C++では、すべての主要なコンパイラ(gccが4.xシリーズで導入し、MSVCは64ビットコードで使用します)は、ゼロコスト例外モデルを使用するようになりました。これを読むと 技術論文 Need4Sleepがリンクされているため、テーブル駆動型アプローチとしてリストされています。アイデアは、プログラムの各ポイントに対して、サイドテーブルに登録して、適切なcatch句を見つけられるようにするいくつかの断片を登録することです。正直なところ、古い戦略よりも実装が少し複雑ですが、ゼロコストの名前はfreeは例外をスローしないでください。これを、CPUでのブランチの予測ミスと比較してください。一方、例外がスローされると、ペナルティは非常に大きくなりますbecauseテーブルはコールドゾーンに格納されます(そのため、RAMまたはそれ以上)...しかし、例外は例外的ですよね?

要約すると、最新のC++コンパイラでは、例外はエラーコードよりも高速ですが、バイナリが大きくなります(静的テーブルのため)。


徹底するために、3番目の選択肢があります:中絶。ステータスまたは例外を介してエラーを伝播する代わりに、代わりにプロセスを中止することができます。これは、限られた数の状況でのみ適していますが、どちらの選択肢よりも最適化されます。

69
Matthieu M.

C++パフォーマンスに関するテクニカルレポートの草案 のセクション5.4をご覧ください。これは、c ++のtry-catchステートメントのオーバーヘッドに関するものです。

セクションからの抜粋:

5.4.1.1.2「コード」アプローチの時間オーバーヘッド

• On entry to each try-block
    ♦ Commit changes to variables enclosing the try-block
    ♦ Stack the execution context 
    ♦ Stack the associated catch clauses 
• On exit from each try-block
    ♦ Remove the associated catch clauses 
    ♦ Remove the stacked execution context 
• When calling regular functions 
    ♦ If a function has an exception-specification, register it for checking 
• As local and temporary objects are created 
    ♦ Register each one with the current exception context as it is created 
• On throw or re-throw 
    ♦ Locate the corresponding catch clause (if any) – this involves some runtime check (possibly resembling RTTI checks) 
    If found, then: 
    destroy the registered local objects 
    check the exception-specifications of the functions called in-between 
    use the associated execution context of the catch clause 
    Otherwise: 
    call the terminate_handler6
6

場合によります。例外処理のために、コンパイラは何かをしなければなりません-さもなければ、スタックの巻き戻しなどを行うことができませんでした。つまり、はい、例外がスローされない場合でも、例外処理はパフォーマンスを低下させます。どのくらい-これはコンパイラの実装に依存します。

一方、自分で質問する必要があります。エラー処理コードを自分で挿入すると、本当に高速になります(測定します-推測しないでください)。例外と同じことができますか(クライアントは例外を無視できません-エラーコードはできます-そして、エラーコードができないスタックアンワインドを行うことができます)。さらに、例外を除き、より保守しやすいようにコードを作成できます。

短い:あなたのコードが非常に非常に非常に非常に非常に時間的に重要でない限り、例外を使用してください。あなたがそれらに対して決定したとしても:最初に測定します。ルールの1つの例外:モジュールの境界を越えて、またはデストラクタで例外をスローするのは悪い考えです。

2
Tobias Langner

それは本当に特定のコンパイラに依存します。

コンパイラが例外を本当に例外的な状態でスローすることを考慮する場合、例外がない場合はオーバーヘッドがゼロですが、例外やコードサイズが大きい場合は時間がかかるスキームを実装できます。

ゼロオーバーヘッドアプローチを実装するには、C++ではコードを動的に変更できないため、スタックフレームと戻りアドレスがわかったら、巻き戻しの場合または破棄する必要がある場合に破棄する必要があるオブジェクトを修正します例外処理コードセクション。したがって、例外をスローするためのコードは、すべての関数呼び出しサイトのグローバルテーブルをチェックして、何をすべきかを判断することができます。

一方、明示的に破棄されるオブジェクトのリストと、通常の実行中の例外処理コードのアドレスを準備することにより、例外のスローを高速化できます。これにより、通常のコードは遅くなりますが、例外処理は速くなり、コードも少し小さくなります。

残念なことに、C++には例外サポートを完全に放棄する標準的な方法がないため、この可能性に何かを払う必要があります。標準ライブラリは例外をスローし、未知のコードを呼び出すコード(たとえば、関数ポインターの使用または仮想メソッドの呼び出し)例外を処理する準備をしてください。

2
6502

メモリの割り当て、削除、別の複雑な関数の呼び出しなどを行う関数にtry catchを追加することをお勧めします。実際には、パフォーマンスの観点からみれば、try catchは少しオーバーヘッドを追加します。

しかし、未知の例外をキャッチするメリットを考えると、非常に役立ちます。優れたプログラミング慣行では、例外的なプログラマーでない限り、コードに何らかの例外処理を追加することを常にお勧めします。

プログラム全体が例外でスタックしているよりも、小さなパフォーマンスの問題をどうして心配しているのでしょうか。

1
CodeRider