deleteの後のNULLへのポインターの自動設定が標準に含まれないのはなぜだろうといつも思っていました。これが処理されると、無効なポインターによるクラッシュの多くは発生しません。しかし、標準がこれを制限する理由はいくつか考えられると言ったので、
性能:
追加の命令により、
delete
のパフォーマンスが低下する可能性があります。
const
ポインターが原因である可能性があります。それから再び、標準は私が推測するこの特別な場合のために何かをすることができたでしょう。
誰もこれを許可しない正確な理由を知っていますか?
Stroustrup自身 答え。抜粋:
C++では、deleteの実装が明示的に左辺値オペランドをゼロにすることを許可しており、実装がそれを実現することを期待していましたが、そのアイデアは実装者に普及していないようです。
しかし、彼が提起する主な問題は、削除の引数が左辺値である必要がないということです。
まず、nullに設定するには、メモリに保存された変数が必要です。確かに、通常は変数にポインターがありますが、計算されたアドレスにあるオブジェクトをdeleteにしたい場合があります。 「無効化」削除では不可能です。
次にパフォーマンスがあります。 deleteが実行された直後にポインターがスコープから出るようにコードを書いたかもしれません。 nullを入力するのは時間の無駄です。そして、C++は「必要ないのですか?それでお金を払う必要はない」というイデオロギーを持つ言語です。
安全性が必要な場合は、サービスにさまざまなスマートポインターが用意されているか、独自のスマートポインターを作成できます。
そのメモリを指す複数のポインターを持つことができます。削除用に指定したポインターがnullに設定されているが、他のすべてのポインターがnullに設定されていない場合、誤った安心感が生じます。ポインターは、アドレス、数字にすぎません。同様に、間接参照操作のintである場合もあります。私のポイントは、すべてのポインターをスキャンして、削除したばかりの同じメモリーを参照しているポインターを見つけ、それらも同様にヌルにする必要があることです。言語はそのために設計されていないため、そのアドレスのすべてのポインターをスキャンしてそれらを無効にするのは計算量が多くなります。 (他のいくつかの言語は、異なる方法で同様の目標を達成するために参照を構造化しますが。)
ポインターは複数の変数に保存できますが、これらの1つをNULLに設定すると、他の変数に無効なポインターが残ります。したがって、実際にはあまり利益を得ることはなく、誤った安心感を生み出す可能性が高くなります。
それに加えて、あなたが望むことをする独自の関数を作成することができます:
template<typename T>
void deleten(T *&ptr) {
delete ptr;
ptr = NULL;
}
本当に必要はないので、削除する必要があるのは、単なるポインタではなく、ポインタからポインタを取得するからです。
delete
はほとんどデストラクターで使用されます。その場合、メンバーをNULLに設定しても意味がありません。数行後、最後の}
、メンバーはもう存在しません。割り当て演算子では、通常、削除の後に割り当てが続きます。
また、次のコードは違法になります。
T* const foo = new T;
delete foo;
別の理由があります。 deleteが引数をNULLに設定すると仮定します。
int *foo = new int;
int *bar = foo;
delete foo;
BarをNULLに設定する必要がありますか?これを一般化できますか?
ポインタの配列があり、2番目のアクションが空の配列を削除することである場合、メモリが解放される直前に各値をnullに設定しても意味がありません。 nullにしたい場合は、nullを書き込んでください:)
C++を使用すると、独自の演算子newを定義して、たとえば独自のプールアロケーターを使用するように削除できます。これを行うと、newを使用して、厳密にはアドレスではなく、プール配列内のインデックスを使用して削除することができます。このコンテキストでは、NULL(0)の値は正当な意味を持つ場合があります(プール内の最初のアイテムを参照)。
したがって、引数にNULLを自動的に設定して削除すると、必ずしも意味がなくなります-値を無効な値に設定します。無効な値は常にNULLであるとは限りません。
C++の哲学は、「使用する場合にのみ支払います」です。あなたの質問に答えるかもしれません。
また、削除されたメモリを回復する独自のヒープを持つこともあります。変数によって所有されていないポインターもあります。または、いくつかの変数に格納されたポインター-そのうちの1つだけをゼロにすることもできます。
ご覧のとおり、多くの問題と考えられる問題があります。
ポインターを自動的にNULLに設定しても、不適切なポインターの使用に関する問題のほとんどは解決されません。回避できる唯一のクラッシュは、2回削除しようとした場合です。そのようなポインターでメンバー関数を呼び出すとどうなりますか?まだクラッシュします(メンバー変数にアクセスすると仮定します)。 C++は、NULLポインターで関数を呼び出すことを制限しません。また、パフォーマンスの観点からもそうするべきではありません。