12

通常は絶対に失敗しない関数があるとします。たとえば、次のようになります。

std::string convert_integer_to_string(int x);

原則として、これは の候補になりnoexceptます。ただし、実装には動的メモリ管理が含まれる可能性が最も高いため、演算子でメモリを割り当てるときに常にstd::bad_allocnewをスローする可能性があります。

関数に noexcept のアノテーションを付けることをお勧めしますか?

実際的な観点からは、メモリ不足の状況を合理的な方法で処理することは非常に困難です。ほとんどのプログラムは、十分なメモリが利用可能であると想定しています。関数が をスローstd::terminateした場合に発生するように、 を呼び出すことは、その場合は合理的であるように思われます。noexceptstd::bad_alloc

私にとってnoexceptは、ある種のドキュメントです。ユーザー (またはオプティマイザー) が、この関数が決してスローしないと安全に想定できるという約束です。メモリ不足の状況を気にしないアプリケーションをプログラミングしている場合でも、それは有効な仮定です。

最も安全な推奨事項は、例外がスローされる可能性があるnoexcept場合は使用しないことだと思います。std::bad_alloc一方で、noexceptメモリ不足の状況を気にしない (つまり、std::terminateOK の場合) と仮定すると、とにかく使用する利点があるかどうか疑問に思います。

4

2 に答える 2

14

関数が何らかの理由で例外をスローする可能性がある場合は、たとえそれが であっても、それを として宣言しないstd::bad_allocでください。実際に例外をスローできず、それが実際に問題になる関数は比較的少数です。関数の主な必要性は、例外が発生した場合に使用可能なエラー回復オプションを検出できるようにすることです。たとえば、move 構築がスローされないと仮定して、オブジェクトを挿入するときに move 構築を使用できます。ムーブ コンストラクションがスローされる可能性がある場合、強力な例外セーフ操作を実装するときに、ムービング オブジェクトを使用して例外を回復することはできません。したがって、タイプの移動構築が失敗する可能性がある場合、 のインスタンス化はオブジェクトを移動できませんが、それらをコピーする必要があります。noexceptnoexceptstd::vector<T, A>Tstd::vector<T, A>

特に、虚偽のドキュメントとして使用しないnoexceptでください。関数が実際にスローできる場合、それは契約違反です。この違反が発生した場合、システムが一定レベルの定義済みの動作で反応するという事実は、それを利用する必要があるという意味ではありません。...そして、単純なプログラムはおそらく回復せず、メモリが不足すると死ぬだけですが、実際のプログラムは、死ぬときに残した混乱を回復するために少なくとも十分な状態を保存する必要があるかもしれません。つまり、それはどの関数にも受け入れられませんプログラムを強制終了することを決定します (もちろん、関数の意図が文書化されている場合を除きます)。

于 2013-08-11T21:51:48.810 に答える
3

メモリ不足の例外についてあまり心配するかどうかはわかりません。

一部の OS (少なくとも Linux) では、メモリが不足したときのデフォルトの動作は、OS によって ( oom killerによって) 強制終了されます。これはメモリに書き込むときに発生し (メモリを割り当てたときではありません)、クリーンアップ コードを実行する機会が与えられません。この機能はメモリオーバーコミットと呼ばれます

メモリが不足しているという情報が得られたとしても、これらのエラーを適切に処理するのは非常に困難です。例外ハンドラがメモリを割り当てないようにする必要があります。これには、そのエラー ハンドラーからのすべての関数が含まれます。途中でトリガーされた可能性のある一般的な例外ハンドラー (ログなど) がメモリを使用しないようにする必要もあります。通常、期待できる最善の方法は、プログラムをシャットダウンする前に簡単なクリーンアップを行うことです。

std::nothrowを使用して、例外を使用せずに割り当ての結果を確認することもできることに注意してください(つまり、OS を提供すると、実際に割り当て時にその情報が通知されます)。失敗する可能性があると思われる大きな割り当てを行う場合は、そうするのが理にかなっています。これには、(潜在的に)キャッチされていない例外を処理する代わりに、デバッグがかなり簡単な nullptr を取得できるという優れた特性もあります。

于 2013-08-12T14:40:02.807 に答える