137

削除後の NULL へのポインターの自動設定が標準の一部ではないのはなぜだろうといつも思っていました。これが処理されれば、無効なポインターによるクラッシュの多くは発生しなくなります。しかし、標準がこれを制限した理由はいくつか考えられます。

  1. パフォーマンス:

    命令を追加すると、パフォーマンスが低下する可能性がありdeleteます。

  2. constポインターのせいかもしれません。

    次に、標準は、この特殊なケースに対して何かを行うことができたと思います。

これを許可しない正確な理由を誰かが知っていますか?

4

12 に答える 12

159

Stroustrup 自身が答えます。抜粋:

C++ では、delete の実装で左辺値オペランドをゼロにすることが明示的に許可されており、私は実装がそれを行うことを望んでいましたが、そのアイデアは実装者に普及していないようです。

しかし、彼が提起する主な問題は、delete の引数が左辺値である必要はないということです。

于 2009-04-01T08:23:00.000 に答える
68

まず、null に設定するには、メモリに格納された変数が必要です。確かに、通常は変数にポインターがありますが、計算されたばかりのアドレスにあるオブジェクトを削除したい場合があります。「無効化」削除では不可能です。

次にパフォーマンスです。削除が完了した直後にポインタが範囲外になるようにコードを記述している可能性があります。null で埋めるのは時間の無駄です。そして、C++ は「必要ないのならお金を払う必要はない」というイデオロギーを持つ言語です。

安全性が必要な場合は、さまざまなスマート ポインターが提供されているか、独自のポインターを作成することができます。

于 2009-04-01T07:56:19.907 に答える
42

そのメモリを指す複数のポインタを持つことができます。削除用に指定したポインターが null に設定されても、他のすべてのポインターはそうではなかった場合、誤った安心感が生まれます。ポインターは、アドレス、数値にすぎません。逆参照操作を伴う int である可能性もあります。私のポイントは、すべてのポインターをスキャンして、削除したばかりの同じメモリを参照しているポインターを見つけ、それらを無効にする必要があるということです。言語はそのように設計されていないため、そのアドレスのすべてのポインターをスキャンしてそれらを無効にすると、計算量が多くなります。(他の一部の言語では、同様の目標を別の方法で達成するために参照を構造化しています。)

于 2009-04-01T07:58:03.693 に答える
20

ポインターは複数の変数に保存できます。これらの変数の 1 つを NULL に設定すると、他の変数に無効なポインターが残ります。したがって、実際にはあまり得られず、誤った安心感を生み出している可能性が高くなります.

それに加えて、必要なことを行う独自の関数を作成できます。

template<typename T>
void deleten(T *&ptr) {
  delete ptr;
  ptr = NULL;
}
于 2009-04-01T08:00:37.277 に答える
12

実際にはその必要がなく、ポインタだけでなくポインタからポインタへの削除が必要になるためです。

于 2009-04-01T07:50:52.447 に答える
8

delete主にデストラクタで使用されます。この場合、メンバーをNULLに設定しても意味がありません。数行後、終了時}に、メンバーは存在しなくなります。代入演算子では、通常、削除の後に代入が続きます。

また、次のコードが不正になります。

T* const foo = new T;
delete foo;
于 2009-04-02T08:25:16.600 に答える
6

別の理由があります。delete がその引数を NULL に設定するとします。

int *foo = new int;
int *bar = foo;
delete foo;

bar を NULL に設定する必要がありますか? これを一般化できますか?

于 2010-10-01T03:22:16.040 に答える
5

ポインターの配列があり、2 番目のアクションが空の配列を削除することである場合、メモリが解放されようとしているときに各値を null に設定しても意味がありません。nullにしたい場合は、nullを書き込みます:)

于 2009-04-01T07:52:35.737 に答える
4

C++ では、独自の演算子 new および delete を定義して、たとえば独自のプール アロケータを使用できるようにすることができます。これを行うと、厳密にはアドレスではなく、プール配列のインデックスと言うもので new と delete を使用できます。このコンテキストでは、NULL (0) の値に正当な意味がある場合があります (プール内の最初の項目を参照する)。
そのため、引数に自動的に NULL を設定する delete は、常に意味があるとは限りません - 値を無効な値に設定します。無効な値が常に NULL であるとは限りません。

于 2009-04-01T08:09:49.640 に答える
4

C++ の哲学は、「使用する場合にのみ対価を支払う」です。あなたの質問に答えるかもしれないと思います。

また、削除されたメモリを回復する独自のヒープを持つこともあれば、変数に所有されていないポインターを持つこともあります。または、いくつかの変数に格納されているポインター - そのうちの 1 つだけをゼロにすることができます。
ご覧のとおり、多くの問題と考えられる問題があります。

于 2009-04-01T08:26:12.473 に答える
3

ポインターを自動的に NULL に設定しても、ポインターの使用法が悪いという問題のほとんどは解決されません。回避できる唯一のクラッシュは、2 回削除しようとした場合です。そのようなポインターでメンバー関数を呼び出すとどうなりますか? それでもクラッシュします (メンバー変数にアクセスすると仮定します)。C++ では、NULL ポインターで関数を呼び出すことを制限していません。また、パフォーマンスの観点からもそうすべきではありません。

于 2009-04-01T08:18:14.020 に答える
-2

この質問に変な答えをする人を見かけます。

ptr = NULL; このような単純なステートメントがどのようにパフォーマンスの遅延を引き起こすのでしょうか?

別の答えは、同じメモリ位置を指す複数のポインターを持つことができるということです。確かにできます。この場合、一方のポインターに対する削除操作は、そのポインターのみを NULL にし (削除がポインターを NULL にする場合)、もう一方のポインターは非 NULL で、空いているメモリ位置を指します。

これに対する解決策は、ユーザーが同じ場所を指しているすべてのポインターを削除することでした。内部的には、メモリが解放されていないかどうかを確認する必要があります。ポインターを NULL にするだけです。

Stroustrup は、delete がこのように動作するように設計できた可能性があります。彼は、プログラマーがこれを処理すると考えていました。だから彼は無視した。

于 2016-04-05T05:36:03.887 に答える