C++ 標準によれば、new がメモリの割り当てに失敗した場合、std::bad_alloc 例外がスローされるはずです。しかし、VC6 (または CRT 実装?) などの一部のコンパイラはこれに準拠していないと聞いています。これは本当ですか ?新しいステートメントごとに NULL をチェックすると、コードが非常に見苦しく見えるため、これを求めています。
3 に答える
この点に関して、VC6 はデフォルトで非準拠でした。VC6 がnew
返されました0
(またはNULL
)。
この問題に関する Microsoft の KB 記事と、カスタムnew
ハンドラーを使用した推奨される回避策を次に示します。
VC6 の動作用に記述された古いコードがある場合は、nothrownew.obj
. 実際には、7.0 および 7.1 コンパイラ (VS2002 および VS2003) には、デフォルトで非スローまたはスローのどちらに設定されているかを判断するためのかなり複雑な一連のルールnew
があります。
MSは 8.0 (VS2005) でこれをクリーンアップしたようですnothrownew.obj
。
パラメータを使用して、スローする代わりにnew
戻りたいことを指定できることに注意してください。0
std::bad_alloc
std::nothrow
SomeType *p = new(std::nothrow) SomeType;
これは VC6 で動作するように見えるため、既存のエラー処理をやり直す必要がないように、すべてのコンパイラで同じように動作するようにコードを多かれ少なかれ機械的に修正する方法になる可能性があります。
割り当ての試行後に NULL をチェックすることはほとんど無益であるという (やや物議を醸す) 意見を追加したいと思います。プログラムがそのような状況に遭遇した場合、すぐに終了する以外に何もできない可能性があります。その後の割り当ての試行も失敗する可能性が非常に高くなります。
NULL をチェックしないと、後続のコードで NULL ポインターを逆参照しようとするため、比較的ユニークな (そして簡単にデバッグできる) 終了条件で、プログラムをすばやく終了する傾向があります。
NULL のチェックをやめさせようとしているわけではありません。これは確かに良心的なプログラミングです。ただし、(より多くのメモリを割り当てずに) 回復情報を保存したり、重要度の低いメモリを解放したりできる非常に特殊なケースでない限り、それから多くを得ることはありません。しかし、これらのケースはほとんどの人にとって比較的まれです。
これを考えると、少なくともほとんどの場合、個人的にはコンパイラが bad_alloc をスローすることを信頼します。
C++ 仕様に基づいて、params なしで単純な new を使用すると、常に std::bad_alloc がスローされますが、もちろん、準拠していないコンパイラがいくつか存在する可能性があります。
ただし、C++ に準拠していないコンパイラに準拠するようにコーディングするつもりはありません。VC6 は、この点でそれらの 1 つです。
ただし、ポインターを削除した後は常にポインターを NULL に設定することをお勧めします。そのため、NULL のチェックは引き続き必要です。
そうは言っても、コードをクリーンアップするためのいくつかのオプションがあります。
オプション 1: 独自の新しいハンドラーを設定する
コードをクリーンアップする安全な方法は、最初 にset_new_handlerを呼び出すことです。
次に、ハンドラーで NULL をチェックし、NULL が返された場合はそこに std::bad_alloc をスローします。
例外が好きなら、これが最善の策です。より適切に NULL を返したい場合は、新しいハンドラ内で catch を実行することでそれを行うこともできます。
オプション 2: オーバーロードされた new の使用
C++ 標準ヘッダー ファイルは、空である struct notrow を定義します。この構造体のオブジェクトを new 内で使用して、常に NULL を返すオーバーロードされたバージョンを取得できます。
void* operator new (size_t size, const std::nothrow_t &);
void* operator new[] (void *v, const std::nothrow_t &nt);
だからあなたのコードで:
char *p = new(std::nothrow) char[1024];