nothrow 関連の問題について、権力の輪で興味深い議論があったことは注目に値します。これらを読むことを強くお勧めします:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3227.html
http://www.stroustrup.com/N3202-noexcept.pdf
どうやら、非常に影響力のある人々が、C++ になんらかの自動 nothrow 演繹を追加することに関心を持っているようです。
少し熟考した後、私は自分の立場をほぼ反対に変更しました。以下を参照してください
このことを考慮:
つまりnoexcept、あなたを傷つけ、あなたに利益をもたらします。関数がインライン化されている場合はそうではありません! インライン化されている場合-宣言の noexcept からの利点はまったくありません(宣言と定義が1つになります)...それは、安全のためにコンパイラにこれを強制させたい場合を除きます。安全とは、間違った結果を生成するよりも終了したいということです。
今では明らかなはずです-インライン関数を宣言する意味はありませnoexceptん(すべてのインライン関数がインライン化されるわけではないことに注意してください)。
スローしない関数のさまざまなカテゴリを見てみましょう (スローしないことはわかっています)。
インライン化されていない場合、コンパイラはそれがスローされないことを証明できます --noexcept関数本体を傷つけることはなく (コンパイラは仕様を単に無視します)、呼び出しサイトはこの約束の恩恵を受けます
インライン化されていないため、コンパイラはそれがスローされないことを証明できません --noexcept関数本体を傷つけますが、呼び出しサイトに利益をもたらします (何がより有益かを判断するのは困難です)
インライン化され、コンパイラはそれがスローされないことを証明できます --noexcept目的を果たしません
インライン、コンパイラはそれがスローされないことを証明できません --noexcept呼び出しサイトを傷つけます
ご覧のとおり、nothrowは単純に設計が不適切な言語機能です。例外なしの約束を強制したい場合にのみ機能します。正しく使用する方法はありません。「安全性」は得られますが、パフォーマンスは得られません。
noexceptキーワードは、約束(宣言時)と強制(定義時)の両方として使用されることになりました-完璧なアプローチではないと思います(笑、例外仕様で2回目の刺し傷を負いましたが、まだ正しくありませんでした)。
じゃあ何をすればいいの?
あなたの行動を宣言してください(悲しいかな、言語はここであなたを助けるものは何もありません)!例えば:
void push_back(int k); // throws only if there is no unused memory
noexceptインライン関数を使用しないでください (非常に大きいなど、インライン化される可能性が低い場合を除きます) 。
非インライン関数 (またはインライン化される可能性が低い関数) の場合 -- 呼び出しを行います。より大きな関数は、より小さなnoexceptの負の効果を(比較的)得ます-ある時点で、呼び出し元の利益のためにそれを指定することはおそらく理にかなっています
noexceptmove コンストラクターと move 代入演算子 (およびデストラクタ?) で使用します。それらに悪影響を与える可能性がありますが、そうしないと、特定のライブラリ関数 (std::swap、一部のコンテナー操作) が最も効率的なパスを取りません (または、最良の例外保証を提供しません)。基本的に、(現時点では) 関数でnoexcept operatorを使用する場所では、 noexcept specifierを使用する必要があります。
noexcept関数が行う呼び出しを信頼せず、予期しない動作をさせるよりも死ぬ場合に使用します
純粋な仮想関数 -- 多くの場合、これらのインターフェイスを実装している人を信頼していません。多くの場合、保険を購入することは理にかなっています (指定することによりnoexcept)
さて、他にどのようnoexceptに設計できますか?
2 つの異なるキーワードを使用します。1 つは約束を宣言するためのもので、もう 1 つはそれを実施するためのものです。たとえば、 noexceptとforce_noexcept。実際、強制は実際には必要ありません。それは try/catch + terminate() で実行できます (はい、スタックをアンワインドしますが、その後にstd::terminate()が続くかどうかは誰が気にしますか?)
コンパイラーに、特定の関数内のすべての呼び出しを分析させて、スローできるかどうかを判断させます。そうであり、noexcept の約束がなされた場合 -- コンパイラ エラーが発生します。
スローできるが、スローできないことがわかっているコードの場合、コンパイラーが問題ないことを保証する方法が必要です。次のようにします。
vector<int> v;
v.reserve(1);
...
nothrow { // memory pre-allocated, this won't throw
v.push_back(10);
}
promise が破られた場合 (つまり、誰かがベクトル コードを変更し、他の保証を提供するようになった場合) -- 未定義の動作。
免責事項: このアプローチは非現実的すぎる可能性があります。