26

これは、コード レビュー コメントの 1 つとして取り上げられました。

オブジェクトに対して delete を呼び出す前に NULL をチェックするのは良い考えですか?

delete 演算子が内部的に NULL をチェックし、冗長であることは理解していますが、演算子はオーバーロードされる可能性があるため、引数は delete であり、オーバーロードされたバージョンが NULL をチェックしない場合、クラッシュする可能性があります。では、delete がオーバーロードされた場合、いつオーバーロードされた場合に NULL をチェックするかどうかを確認するのは安全で合理的​​でしょうか? 私の理解では、オーバーロードされた削除がNULLチェックを処理する最初のケースを想定するのは合理的であり、レビューポイントは適切ではありません。どう思いますか?

4

11 に答える 11

35

いいえ、null をチェックしません。標準は、それdelete (T*)0;が有効であると述べています。コードが複雑になるだけで、何のメリットもありません。がオーバーロードされている場合operator deleteは、演算子の実装で null をチェックすることをお勧めします。コード行とバグを保存するだけです。

編集:この回答は受け入れられ、支持されましたが、私の意見では、あまり有益ではありませんでした。ここでのすべての回答には欠けている部分が 1 つあります。良心のために、この最後の部分をここに追加させてください。

標準では、少なくとも C++03 以降、[basic.stc.dynamic] で実際に述べています。

ライブラリ内のデフォルト バージョンを含む、C++ プログラムで定義されたすべての割り当ておよび/または割り当て解除関数は、3.7.4.1 および 3.7.4.2 で指定されたセマンティクスに準拠する必要があります。

参照されているセクション、および他の回答にリストされている標準の他の場所では、ヌルポインターを渡すセマンティクスはノーオペレーションであると言われています。

于 2010-09-29T11:45:31.513 に答える
19

をオーバーロードする場合operator deleteは、常に をチェックする必要がありNULLます。そうしないと、セマンティクスが壊れます。

于 2010-09-29T11:46:13.570 に答える
7

オブジェクトに対して delete を呼び出す前に NULL をチェックするのは良い考えですか?

いいえ!

int *p = NULL;
delete p ; //no effect

標準は言う [セクション 5.3.5/2]

オペランドがクラス型の場合、前述の変換関数を呼び出すことによってオペランドがポインタ型に変換され、変換されたオペランドがこのセクションの残りの部分で元のオペランドの代わりに使用されます。いずれの場合も、delete のオペランドの値がヌル ポインターの場合、操作は無効になります

さらにセクションでは18.4.1.1/13

void operator delete(void* ptr) throw();

void operator delete(void* ptr, const std::nothrow_t&) throw();

デフォルトの動作:

ptr の null 値の場合、何もしません

— ptr のその他の値は、デフォルト演算子 new への呼び出しによって以前に返された値であり、演算子 delete(void*) (17.4.3.7) への介入呼び出しによって無効にされませんでした。そのような ptr の非 null 値の場合、デフォルト演算子 new への以前の呼び出しによって割り当てられたストレージを再利用します。

編集

ここでジェームス・カンゼは次のように述べています。

チェックするのは、オペレーターの削除 (または削除[]) の責任です。標準は、null ポインターが与えられないことを保証しません。標準では、null ポインターが指定された場合、ノーオペレーションである必要があります。または、実装がそれを呼び出すことが許可されていること。最新のドラフトによると、「割り当て解除関数に指定された最初の引数の値は null ポインター値である可能性があります。その場合、割り当て解除関数が標準ライブラリで提供されている場合、呼び出しは効果がありません。」「標準ライブラリで提供されるものである」という意味が何を意味するのかはよくわかりません---文字通りに解釈されます.彼の機能は標準ライブラリによって提供されるものではないため、文は適用されないようです. . でも、なんとなく、腑に落ちません。

于 2010-09-29T11:46:38.983 に答える
6

deleteあなたが期待するように振る舞うのはオーバーロードの責任だと思いますdelete。つまり、NULL ポインターをノーオペレーションとして処理する必要があります。

そのため、オーバーロードされた削除を呼び出すときは、NULL をチェックしないでください。正しく実装するには、オーバーロードされた削除に依存する必要があります。

于 2010-09-29T12:48:28.320 に答える
3

null をチェックする必要はありません。delete 演算子は null に対して chck を実行するため、追加のチェックは必要ありません。

于 2010-09-29T11:48:25.487 に答える
3

delete (T*)0;は有効で何もしません。同様に、free(NULL);も有効で何もしません。演算子をオーバーロードする場合delete、実装は同じセマンティクスを保持する必要があります。標準は標準がどのように機能するかdeleteを示していますが、オーバーロードされたものがどのように動作するかを示しているとは思いませんdelete。標準/デフォルトの動作との一貫性のために(T*)0、入力として許可する必要があります。

于 2010-09-29T11:53:16.160 に答える
3

標準ドキュメントの18.5.1.1.13からdelete

デフォルトの動作: ptr が null の場合、何もしません。それ以外の場合は、以前の operator new の呼び出しによって割り当てられたストレージを再利用します。

したがって、デフォルトでチェックする必要はありません..

于 2010-09-29T11:54:30.587 に答える
2

チェックしなくてもいいのでは。誰かがペットをオーバーロードした場合、NULL を使用することは彼の責任です。

于 2010-09-29T13:31:56.540 に答える
2

削除する前に NULL をチェックする必要はありません。誰かがdelete標準的な方法で動作しないものをオーバーロードしている場合、それ本当の問題です。過負荷のタスクを軽視するdeleteべきではなく、NULL をチェックしてアクションを実行しないなどの予期される動作を常にサポートする必要があります。

ただし、価値のあることとして、たとえばポインターも削除しようとしている場合を除き、削除したばかりのポインターには常にゼロを割り当てることを忘れないでください。

void MyObj::reset()
{
    delete impl_;
    impl_ = 0;    // Needed here - impl_ may be reused / referenced.
}

MyObj::~MyObj()
{
    delete impl_; // No need to assign here as impl_ is going out of scope.
}
于 2010-09-29T12:46:41.600 に答える
1

質問には不完全な情報が含まれていると思います。NULL が渡された場合、デフォルトの削除演算子で未定義の動作になる、サポートしなければならない 1 つのコンパイラ/プラットフォーム構成がまだあるため、私のショップでは、コーディング標準で削除の前に NULL のチェックがまだあります。元の投稿者が同様の状況にある場合は、NULL をチェックするポイントがあります。それ以外の場合は、コーディング標準を変更してください。

于 2010-09-29T13:50:49.123 に答える
0

C++ のちょっとした知識: NULL は組み込みの概念ではありません。はい、私たちはそれが何を意味するか知っていますが、C++0X より前の C++ では、ヌル ポインターの概念は単に値 0 です。NULL は通常、0 に展開されるプラットフォーム固有のマクロです。

C++0X では、単純なゼロよりも明確で、bool 以外の整数型に変換できず、NULL よりも優れた概念 (または、NULL の背後にある概念のより優れた実装) である nullptr を取得しています。

于 2010-09-29T13:29:13.707 に答える