10

私は学生で、C++ についての知識はほとんどありませんが、それを拡張しようとしています。これは哲学的な質問です..私は何かを実装しようとしているわけではありません。

以来

#include <new> 
//...
T * t = new (std::nothrow) T();
if(t)
{
    //...
}
//...

例外を非表示にします。単純な割り当てに比べて例外の処理が重いため、単純な割り当てが成功したかどうかを確認するために を使用する必要があることを考えるとif(t)、なぜ通常のnew T()方法があまり良い習慣と見なされないのでしょうtry-catch()か (そうでない場合は、プログラムが死ぬのを見るだけです)??

newを使用する場合と比較して、通常の割り当ての利点は何nothrow newですか? その場合の例外のオーバーヘッドは重要ではありませんか?

また、割り当てが失敗したとします (たとえば、システムにメモリが存在しません)。その状況でプログラムができることはありますか、それとも正常に失敗するだけですか。すべてが予約されている場合、ヒープ上の空きメモリを見つける方法はありませんか?

割り当てが失敗し、 anstd::bad_allocがn の場合、オブジェクト (たとえば a ) を割り当てるのに十分なメモリがないため、例外を格納するのに十分なメモリがあるthrowとどのように仮定できますか??new int

御時間ありがとうございます。質問がルールに沿っていることを願っています。

4

6 に答える 6

10

例外の処理は単純な if(t) に比べて重いため、単純な割り当てが成功したかどうかを確認するために try-catch() を使用する必要があることを考えると、通常の new T() があまり良い習慣と見なされないのはなぜですか (そうでない場合は、プログラムが死ぬのを見るだけです)?? notrow new を使用する場合と比較して、通常の new 割り当ての利点は何ですか? その場合の例外のオーバーヘッドは重要ではありませんか?

例外を使用することのペナルティは確かに非常に重いですが、(適切に調整された実装では)例外がスローされたときにのみペナルティが支払われます。あなたの例。

例外の利点は、コードが単純になることです。複数のオブジェクトを割り当てる場合、「A を割り当てます。(A) { B を割り当てます。(B) などを割り当てます...」を行う必要はありません。例外とメインラインの両方の場合のクリーンアップと終了は、RAII によって自動的に処理されるのが最適です (一方、手動でチェックしている場合は、手動で解放する必要があるため、メモリ リークが非常に簡単になります)。

また、割り当てが失敗したとします (たとえば、システムにメモリが存在しません)。その状況でプログラムができることはありますか、それとも正常に失敗するだけですか。すべてが予約されている場合、ヒープ上の空きメモリを見つける方法はありませんか?

できることはたくさんありますが、最善の方法は、書かれているプログラムによって異なります。失敗して終了すること (適切にまたはそうでない場合) は、確かに 1 つのオプションです。もう 1 つは、事前に十分なメモリを確保して、プログラムがその機能を実行できるようにすることです (機能やパフォーマンスが低下する可能性があります)。独自のメモリの一部を解放できる場合があります (たとえば、必要に応じて再構築できるキャッシュを保持している場合)。または (サーバー プロセスの場合)、サーバーは現在の要求の処理を拒否 (または新しい接続の受け入れを拒否) する可能性がありますが、クライアントが接続を切断しないように実行を継続し、メモリが失われると再び動作を開始できます。戻り値。または、インタラクティブ/GUI アプリケーションの場合は、

割り当てが失敗し、std::bad_alloc がスローされた場合、オブジェクト (たとえば、新しい int) を割り当てるのに十分なメモリがないため、例外を格納するのに十分なメモリがあるとどのように想定できますか??

いいえ、通常、標準ライブラリは、通常、事前に少量のメモリを割り当てることによって、メモリが使い果たされた場合に例外が発生するのに十分なメモリがあることを保証します。

于 2010-12-31T18:47:53.903 に答える
6

Notrow は、主に、例外のないコードを記述したい組み込みシステム開発者をサポートするために C++ に追加されました。malloc() の後に配置 new を行うよりも優れた解決策として、メモリ エラーをローカルで実際に処理したい場合にも役立ちます。そして最後に、NULL のチェックに基づく C++ プログラミング スタイル (当時は最新のもの) を引き続き使用したい人にとっては不可欠です。[私はこの解決策を自分で提案しました。私が提案したものの、反対票を投じられなかった数少ないものの1つです:]

参考までに: メモリ不足で例外をスローすることは、設計に非常に敏感であり、実装が困難です。たとえば、文字列をスローすると、文字列がヒープ割り当てを行うため、二重の障害が発生する可能性があるためです。実際、ヒープがスタックにクラッシュしたためにメモリが不足している場合は、一時的なものを作成することさえできない可能性があります! この特定のケースは、標準の例外がかなり制限されている理由を説明しています。また、そのような例外をかなりローカルでキャッチしている場合、値ではなく参照でキャッチする必要があるのはなぜですか (コピーが二重障害を引き起こす可能性を避けるため)。

これらすべてにより、nothrow は重要なアプリケーションにより安全なソリューションを提供します。

于 2011-01-01T02:18:46.427 に答える
4

newnewではなく通常を使用するnothrow理由は、通常、各関数の戻り値を明示的にチェックするよりも例外が好まれる理由に関連していると思います。メモリを割り当てる必要があるすべての関数が、メモリが見つからない場合に何をすべきかを必ずしも知っているわけではありません。たとえば、メモリをサブルーチンとして何らかのアルゴリズムに割り当てる深くネストされた関数は、メモリが見つからない場合に取るべき適切な一連のアクションがおそらくわかりません。のバージョンの使用new例外をスローすると、サブルーチン自体ではなく、サブルーチンを呼び出すコードがより適切なアクションを実行できるようになります。これは、何もせずにプログラムが終了するのを監視する (小さなおもちゃのプログラムを作成している場合はまったく問題ありません) か、メモリの破棄を開始するように高レベルのプログラム コンストラクトに信号を送信するのと同じくらい簡単です。

あなたの質問の後半に関しては、プログラムがメモリを使い果たした場合に、メモリをより多く利用できるようにするためにできることが実際にある可能性があります。たとえば、古いデータをキャッシュするプログラムの一部があり、リソースが逼迫するとすぐにすべてを追い出すようにキャッシュに指示することができます。重要度の低いデータをディスクにページアウトする可能性があり、おそらくメモリよりも多くのスペースがあります。このようなトリックがたくさんあり、例外を使用することで、すべての緊急ロジックをプログラムの先頭に配置し、割り当てを行うプログラムのすべての部分で bad_alloc をキャッチせず、代わりにそれを許可することができます。上まで伝播します。

最後に、通常、メモリが不足している場合でも例外をスローすることができます。多くの C++ 実装では、スタック (またはその他の非ヒープ メモリ セグメント) に例外用のスペースが予約されているため、ヒープがスペースを使い果たした場合でも、例外用のメモリを見つけることができます。

お役に立てれば!

于 2010-12-31T18:30:34.877 に答える
3

「高すぎる」という理由で例外を回避することは、時期尚早の最適化です。例外がスローされない場合、try/catch のオーバーヘッドは実質的にありません。

その状況でプログラムができることはありますか

通常はありません。システムにメモリがなければ、おそらくログに何も書き込めなかったり、stdout に出力できなかったりします。もしあなたが記憶を失っているなら、あなたはかなりめちゃくちゃです。

于 2010-12-31T18:26:49.613 に答える
2

メモリ不足はまれなイベントであると予想されるため、発生時に例外をスローするオーバーヘッドは問題になりません。実装は、をスローするために必要なメモリを「事前に割り当てる」ことがstd::bad_allocでき、プログラムがメモリ不足になった場合でも確実に使用できるようにします。

null を返す代わりにデフォルトで例外をスローする理由は、割り当てのたびに null チェックを行う必要がなくなるためです。多くのプログラマーはそれを気にしません。また、プログラムが割り当てに失敗した後もヌル ポインターを使用し続けると、問題の本当の原因を示さないセグメンテーション違反のようなもので後でクラッシュする可能性があります。例外を使用すると、OOM 条件が処理されない場合、プログラムはすぐに終了し、実際に問題が発生したことを示すエラーが表示されるため、デバッグがはるかに簡単になります。

また、メモリ不足の状況で例外がスローされた場合の処理​​コードを記述するのも簡単です。すべての割り当ての結果を個別にチェックする代わりにcatch、コール スタックの上位にブロックを配置して、さまざまな場所から OOM 状態をキャッチできます。プログラム。

于 2010-12-31T18:36:59.730 に答える
-1

Symbian C++ では逆に動作します。OOM時に例外をスローしたい場合は、あなたがしなければならない

T* t = new(ELeave) T();

そして、OOM が奇妙である場合に新しい例外をスローするロジックについては正しいです。対処可能なシナリオが突然プログラムの終了になります。

于 2010-12-31T18:31:59.093 に答える