委員会は、例外仕様で許可されていない例外をスローする (しようとした) コードが不正と見なされる可能性を明確に考慮し、その考えを拒否しました。$15.4/11 によると:
実装は、式が実行されたときに含まれる関数が許可しない例外をスローするか、スローする可能性があるという理由だけで、式を拒否してはなりません。[ 例:
extern void f() throw(X, Y);
void g() throw(X) {
f(); // OK
}
への呼び出しf
は整形式ですが、呼び出されたときに、許可されていないf
例外がスローされる可能性があります。—終わりの例]Y
g
決定のきっかけとなったものや、他に何があったかに関係なく、これが事故や見落としの結果ではないことは明らかです.
この決定が行われた理由については、少なくとも一部は、ムーブ セマンティクスなど、C++11 の他の新機能との相互作用に遡ります。
Move セマンティクスは、例外の安全性 (特に強力な保証) の実施/提供をより困難にする可能性があります。コピーを行っているときに何か問題が発生した場合、トランザクションを "ロールバック" するのは非常に簡単です。作成したコピーをすべて破棄し、メモリを解放すると、オリジナルはそのまま残ります。コピーが成功した場合にのみ、オリジナルを破棄します。
移動セマンティクスを使用すると、これはより困難になります。オブジェクトの移動中に例外が発生した場合、元の順序を復元するには、既に移動したものを元の場所に戻す必要がありますが、移動コンストラクターまたは移動代入演算子がスローする可能性があるため、元のオブジェクトを復元しようとするために物事を元に戻そうとするプロセスで別の例外が発生する可能性があります。
これを、C++11 がムーブ コンストラクターとムーブ代入演算子をいくつかの型に対して自動的に生成できる/生成するという事実と組み合わせます (ただし、制限の長いリストがあります)。これらは必ずしも例外のスローを保証するものではありません。ムーブ コンストラクターを明示的に記述している場合、ほとんどの場合、それがスローされないようにする必要があります。これは通常、非常に簡単に行うことができます (通常はコンテンツを「盗む」ため、通常はいくつかのポインターをコピーするだけです --例外なく簡単に行うことができます)。ただし、テンプレートのような単純なものであっても、急ぐと非常に難しくなりstd:pair
ます。コピーする必要があるものと移動できるものとのペアは、うまく処理することが難しくなります。
つまり、コンパイル時にnothrow
(および/またはthrow()
) 強制することを決定した場合、未知の (しかしおそらくかなりの量の) コードの一部が完全に壊れていたことになります。新しいコンパイラでコンパイルすることさえできます。
これに加えて、廃止されたわけではありませんが、動的例外仕様が言語に残っているため、実行時に少なくともいくつかの例外仕様を強制することになるという事実がありました。
したがって、彼らの選択は次のとおりです。
- 多くの既存のコードを壊す
- 移動セマンティクスを制限して、適用されるコードを大幅に減らす
- (C++03 のように) 続行して、実行時に例外指定を強制します。
これらの選択肢のいずれかが気に入った人はいないと思いますが、3 番目の選択肢が最後に悪かったようです。