削除してもポインタがNULLに設定されないのはなぜですか?


127

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

  1. パフォーマンス:

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

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

    そして、スタンダードはこの特別なケースのために何かをしたかもしれません。

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

回答:


150

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

C ++では、削除の実装で明示的に左辺値のオペランドをゼロにすることが許可されており、実装でそれが実行されることを期待していましたが、そのアイデアは実装者に人気があるようには見えません。

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


これにはもう少し説明が必要かもしれません。私は彼が何を言っているのかさえわかりません...私がそれを手に入れるまでこれを研究するために数時間を費やすことができるときに私は後で戻ってくる必要があると思います。または、回答をより詳しく理解するために詳しく説明することもできます。
ガブリエルステープルズ

63

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

次にパフォーマンスが始まります。削除が完了するとすぐにポインターがスコープから外れるようにコードを記述した可能性があります。nullで埋めるのは時間の無駄です。そしてC ++は「それを必要としないのか?それならあなたはそれにお金を払う必要がない」という思想を持つ言語です。

安全性が必要な場合は、サービスにさまざまなスマートポインタが用意されています。または、独自のポインタを作成することもできます。


4
よく見られない住所であっても、計算された住所に関して良い点
スネマーチ2009

計算したばかりのアドレスにあるオブジェクトを削除したい場合があると言ったときに、新しい配置について話していますか。???
デストラクタ

@PravasiMeetいいえ、私は何かのようなものを意味しますdelete (ptr + i)
シャープトゥース

39

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


19

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

その上、あなたが望むことをするあなた自身の関数を作成することができます:

template<typename T>
void deleten(T *&ptr) {
  delete ptr;
  ptr = NULL;
}

12

なぜなら、実際には何もする必要がなく、削除するのに、ポインターだけでなくポインター間を削除する必要があるからです。


真実ですが、同じオーバーヘッドが発生します
2009

7

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

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

T* const foo = new T;
delete foo;

6

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

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

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


5

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


4

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


4

C ++の哲学は、「使用した場合にのみ支払う」ことです。質問の答えになるかもしれません。

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


3

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


-1

私はこの質問に奇妙な答えをする人々を見かけます。

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

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

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

Stroustrupは、このように機能するように削除を設計できたはずです。プログラマーがこれを処理するだろうと彼は思った。それで彼は無視した。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.