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