- 私がスローしないとわかっている関数の例はたくさんありますが、コンパイラーがそれ自体で決定することはできません。このような場合はすべて、関数宣言にnoexceptを追加する必要がありますか?
noexcept
関数インターフェイスの一部であるため、注意が必要です。特に、ライブラリを作成している場合、クライアントコードはnoexcept
プロパティに依存する可能性があります。既存のコードを壊す可能性があるため、後で変更するのは難しい場合があります。アプリケーションでのみ使用されるコードを実装する場合は、それほど心配する必要はありません。
スローできない関数がある場合は、それがとどまるのが好きか、それともnoexcept
将来の実装を制限するだろうかと自問してください。たとえば、例外をスローすることにより(たとえば、単体テストの場合)不正な引数のエラーチェックを導入したり、例外の仕様を変更する可能性のある他のライブラリコードに依存したりする場合があります。その場合は、保守的にして省略した方が安全noexcept
です。
一方、関数がスローしてはならないという確信があり、それが仕様の一部であることが正しい場合は、宣言する必要がありnoexcept
ます。ただし、noexcept
実装が変更された場合、コンパイラは違反を検出できないことに注意してください。
- noexceptの使用についてもっと注意する必要があるのはどの状況ですか?暗黙のnoexcept(false)を回避できるのはどの状況ですか?
最大の影響を与える可能性が高いため、集中すべき関数のクラスは4つあります。
- 移動操作(割り当て演算子の移動とコンストラクターの移動)
- スワップ操作
- メモリ割り当て解除子(演算子の削除、演算子の削除[])
- デストラクタ(ただし、ユーザー
noexcept(true)
が作成しない限り、これらは暗黙的に行われますnoexcept(false)
)
これらの関数は一般的にnoexcept
である必要があり、ライブラリ実装がnoexcept
プロパティを利用できる可能性が最も高いです。たとえば、std::vector
強力な例外保証を犠牲にすることなく、スローしない移動操作を使用できます。それ以外の場合は、要素のコピーにフォールバックする必要があります(C ++ 98の場合と同様)。
この種の最適化はアルゴリズムレベルで行われ、コンパイラーの最適化に依存しません。特に要素のコピーにコストがかかる場合は、大きな影響を与える可能性があります。
- noexceptを使用した後、パフォーマンスの改善が見られるのはいつ現実的に期待できるでしょうか?特に、noexceptを追加した後、C ++コンパイラーがより良いマシンコードを生成できるコードの例を示します。
noexcept
例外なしの仕様に対する利点、またはthrow()
標準により、コンパイラーがスタックの巻き戻しに関してより自由にコンパイラーを使用できるようになります。このthrow()
場合でも、コンパイラーはスタックを完全に巻き戻す必要があります(オブジェクト構造とまったく逆の順序で実行する必要があります)。
一方、このnoexcept
場合、その必要はありません。スタックを巻き戻す必要はありません(ただし、コンパイラーは引き続き巻き戻すことができます)。この自由により、常にスタックを巻き戻すことができるというオーバーヘッドが低くなるため、コードをさらに最適化できます。
noexcept、スタックの巻き戻しとパフォーマンスに関する関連する質問では、スタックの巻き戻しが必要な場合のオーバーヘッドについて詳しく説明しています。
また、Scott Meyersの本「Effective Modern C ++」、「Item 14:Declare functions noexcept not exclude発信しないときは例外になる」も読んでください。
move_if_nothrow
(またはwhatchamacallit)では、例外なくmove ctorがある場合、パフォーマンスが向上します。