web-dev-qa-db-ja.com

C ++ 11で非推奨のthrow-list

cppreference でわかるように、古典的な「スロー」宣言リストはC++ 11で非推奨になりました。このメカニズムを終了する理由は何ですか?また、どの例外が私の機能をスローするかを指定する必要がありますか?

44
Peregring-lk

より詳細な推論については、以下を参照してください: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3051.html

上記の国家機関のコメントで表されているように、例外仕様は実際には有用ではありません。 C++の例外仕様に関する問題については多くの議論がありますが(たとえば、[Sutter02]、[Boost03]を参照)、主な問題は次のとおりです。

  • 実行時チェック:C++例外仕様はコンパイル時ではなく実行時にチェックされるため、すべての例外が処理されたことをプログラマが保証することはできません。実行時障害モード(std :: unexpected()の呼び出し)は、回復に役立ちません。
  • 実行時オーバーヘッド:実行時チェックでは、コンパイラが最適化を妨げる追加コードを生成する必要があります。
  • 汎用コードでは使用不可:汎用コード内では、テンプレート引数の操作からスローされる例外のタイプを知ることは一般的に不可能であるため、正確な例外仕様を記述することはできません。

実際には、2つの形式の例外スロー保証のみが有用です。1つの操作が例外(任意の例外)をスローする場合と、1つの操作が例外をスローしない場合があります。前者は例外仕様を完全に省略することで表現され、後者はthrow()として表現できますが、パフォーマンスを考慮するとめったにありません。

[N3050]は、新しい種類の例外仕様、noexceptを導入します。これは、関数が例外をスローしないことを指定します。 throw()とは異なり、noexceptでは、例外がスローされるかどうかをチェックするコードをコンパイラーに導入する必要がありません。むしろ、noexceptとして指定された関数が例外を介して終了した場合、結果はstd :: terminate()の呼び出しになります。

Noexceptの導入により、プログラマは、追加のオーバーヘッドなしで、実際に役立つ2種類の例外保証を表現できるようになりました。したがって、このペーパーでは、「動的な」例外仕様、つまりthrow(type-id-listopt)として記述された仕様を廃止することを提案します。

48
Peter

Peterが与えた答えは、実装者とユーザーの例外仕様の実際の問題には当てはまりません。

  • 実装者が定義された例外のみをスローするという保証を維持できなかった場合、例外仕様により、プログラムは終了します(より正確には終了ハンドラーを呼び出します)。
  • したがって、ライブラリユーザーとしての例外仕様を使用してメソッドを呼び出すことで、独自のコードmoreを作成し、失敗/終了を起こしやすくなります。ライブラリー関数がメモリー不足(std :: bad_alloc)で実行される場合、キャッチする機会はありませんが、代わりに終了します。
  • したがって、最も可能性の高い障害オプションを伝え、ユーザーにそれらの処理を依頼するという当初の目標は達成されませんでした。
  • 反対側の実装者として、例外仕様を持たない他のメソッドを実際に呼び出すことはできません。これらは呼び出し元を終了させる可能性があるためです。あるべき恐ろしい場所。

結論は、C++がJavaがやった方法を行ったはずだということです。

  • 例外仕様でメソッドを呼び出し、自分で例外仕様を持っている場合は、例外をキャッチするか、独自の例外仕様で例外を指定する必要があります。
  • コンパイラーはこれを強制し、他のランタイム効果はありません。

Noexcept(C++ 11以降)は、同じ概念上の誤りに悩まされます。仕様が守られていない場合、つまり、宣言されていないメソッドがスローされた場合、ランタイム終了も発生するためです。これにより、noexceptを使用して、深刻な場合以外は使用できなくなります( 移動コンストラクターが思い浮かぶ )。

7

Libc ++は、関数から伝播する例外がその例外仕様に違反しているかどうかをチェックし、std::unexpected。これはほとんど役に立たず、関数が自分でスローする例外を単に文書化するよりも悪いです。

4
dupersuper