web-dev-qa-db-ja.com

新規(std :: nothrow)とtry / catchブロック内の新規

慣れているmalloc()とは異なり、newを学習した後、いくつかの調査を行いましたが、失敗した割り当てに対してNULLを返さず、newが成功したかどうかを確認する2つの異なる方法があることがわかりました。 。これらの2つの方法は次のとおりです。

try
{
    ptr = new int[1024];
}
catch(std::bad_alloc& exc)
{
    assert();
};

そして

ptr = new (std::nothrow) int[1024];
if(ptr == NULL) 
    assert();

私は2つの方法で同じ目標を達成できると信じています(もちろん私が間違っている場合は修正してください)。私の質問は次のとおりです。

これは、事実上のc ++プログラミング規則を無視して、読みやすさ、保守性、およびパフォーマンスに完全に基づいて、newが成功したかどうかをチェックするためのより良いオプションです。

39
Anne Quinn

あなたが何をしているかを考えてください。メモリを割り当てています。そして、何らかの理由でメモリ割り当てが機能しない場合は、assertを使用してください。これは、std::bad_allocmainに戻ります。 assertが何もしないリリースビルドでは、プログラムはメモリにアクセスしようとするとクラッシュします。つまり、例外をバブルアップさせるのと同じです。つまり、アプリを停止します。

だから、あなた自身に質問をしてください:あなたは本当にメモリが足りなくなったらどうなるか気にする必要がありますか?アサートするだけの場合は、ランダムなassertsでコードが乱雑にならないため、例外メソッドの方が適しています。例外をmainにフォールバックさせるだけです。

実際にメモリを割り当てることができない場合(つまり、実際に機能を継続できる場合)に特別なコードパスがある場合、コードパスが何であるかによって、例外が適切な場合とそうでない場合があります。コードパスがポインタをnullにすることによって設定された単なるスイッチである場合、nothrowバージョンはより単純になります。代わりに、何か別のことをする必要がある場合(静的バッファーからプルするか、何かを削除するなど)、std::bad_allocはかなり良いです。

50
Nicol Bolas

それは、割り当てが行われている状況に依存します。割り当てが失敗してもプログラムが続行できる場合(呼び出し元にエラーコードが返される可能性があります)、std::nothrowメソッドを使用してNULLを確認します。それ以外の場合は、制御フローの例外を使用することになりますが、これは良い方法ではありません。

一方、プログラムが機能するためにそのメモリを正常に割り当てる必要がある場合は、try-catchを使用して例外をキャッチします(newのすぐ近くにある必要はありません)。そして、プログラムを正常に終了します。

12
Praetorian

純粋なパフォーマンスの観点からは、ほとんど問題になりません。例外処理には固有のオーバーヘッドがありますが、このオーバーヘッドは通常、アプリケーションの可読性と保守のトレードオフに値します。この種のメモリ割り当ての失敗は、アプリケーションの99%のケースでは発生しないはずなので、まれに発生するはずです。

パフォーマンスの観点からは、とにかくパフォーマンスが比較的低いため、通常は標準アロケータを避けたいと思います。

以上のことから、通常、アプリケーションはメモリの割り当てに失敗した場合、適切なエラーメッセージで正常に終了する以外にできることはほとんどなく、NULL定義により割り当ての失敗はスコープを重要な場所から移動するため、新しく割り当てられたリソースをチェックします。

7
Chad