C ++ FAQのこの段落では、構成の使用法delete this
について説明します。4つの制限がリストされています。
制限1から3はかなり合理的に見えます。しかし、なぜ制限4があるので、「調べたり、別のポインターと比較したり、NULLと比較したり、印刷したり、キャストしたり、何かをしたりしてはならない」のでしょうか。
つまりthis
、もう1つの指針です。なぜreinterpret_cast
それをint
または呼び出しprintf()
てその値を出力できないのですか?
C ++ FAQのこの段落では、構成の使用法delete this
について説明します。4つの制限がリストされています。
制限1から3はかなり合理的に見えます。しかし、なぜ制限4があるので、「調べたり、別のポインターと比較したり、NULLと比較したり、印刷したり、キャストしたり、何かをしたりしてはならない」のでしょうか。
つまりthis
、もう1つの指針です。なぜreinterpret_cast
それをint
または呼び出しprintf()
てその値を出力できないのですか?
deleteを呼び出した後の'this'の値は未定義であり、それを使用して行うすべての動作も未定義です。ほとんどのコンパイラは賢明なことをすることを期待しますが、この特定の場合の動作がハードディスクをフォーマットするためのコードを出力することをコンパイラが決定することを(仕様では)妨げるものは何もありません。未定義の動作を呼び出すことは、特定のコンパイラが希望どおりに動作する場合でも、(ほとんど)常に間違いです。
これを回避するには、deleteを呼び出す前にポインターのコピーを(整数として)取得します。
ポインタ(これまたは他のポインタ)を削除した後、ポインタで何もできない理由は、ハードウェアが無効なメモリアドレスをレジスタにロードしようとしてトラップする可能性があるためです(一部の古いマシンはそうしました)。最近のすべてのハードウェアでは問題ないかもしれませんが、標準では、無効なポインター(初期化されていないか削除されている)に対して実行できるのは、ポインター(NULLまたは別の有効なポインターから)に割り当てることだけであるとされています。
あはは!
3.7.3.2 / 4: "...割り当て解除関数は、ポインターによって参照されるストレージの割り当てを解除し、割り当て解除されたストレージの任意の部分を参照するすべてのポインターを無効にします。無効なポインター値を使用した場合の影響(割り当て解除への受け渡しを含む)関数)は未定義です」。
これは、「ポインタの逆参照」ではなく、「値の使用」を示していることに注意してください。
その段落はに固有のものthis
ではなく、削除されたものすべてに適用されます。
そのポインタを使用して実行できるアクションは、そのオブジェクトのクラスメソッドで解釈されるロジックをトリガーし、クラッシュにつながる可能性があるためです。
さて、あなたが指摘する行動のいくつかは明らかに「安全」である可能性がありますが、あなたが呼び出すことができるどのメソッド内で何が起こるかを言うのは難しいです。
投稿から:「それを調べてはいけません、それを別のポインタと比較し、それをNULLと比較し、それを印刷し、それをキャストし、それで何かをします」?
これらのアクションはすべて、未定義のポインターで評価されるオペレーター関連の関数をトリガーできます。キャスティングのためのIdem。
reintepret_castを実行する場合、それはおそらく別の話であり、reinterpretは(私が知る限り)メソッド呼び出しを伴わずに少しずつ再解釈するため、おそらくうまくいく可能性があります。
同じ理由で、他のポインタを削除してから、そのポインタに対して操作を実行することはありません。
b / cこれが現在参照しているアドレス、未定義、そしてそこに何があるのかわからない...
マルチスレッドプログラムではdelete
、ポインタを押すとすぐに、別のスレッドによって空き領域が割り当てられ、によって使用される領域が上書きされthis
ます。return
シングルスレッドプログラムでも、ingの前に呼び出すものに細心の注意を払わない限り、後で行うdelete this
ことはメモリを割り当て、以前は。が指していたものを上書きする可能性がありますthis
。
デバッグモードでコンパイルされたMicrosoftVisualC ++実行可能ファイルではdelete
、ポインターを実行すると、そのメモリが0xCCテストパターンですぐに上書きされ(初期化されていない変数もこのパターンで初期化されます)、このようなダングリングポインターのバグを特定するのに役立ちます。
これは、Fireの総数が特定の数に達した場合に、Fireオブジェクトのコンストラクターが最も古いFireを削除する、オンラインでプレイ可能なゲームのバグを修正したときのことを思い出させます。削除されたFireは、新しいFireを作成する親Fireである場合がありました—バム、ダングリングポインタのバグ!このバグが完全に予測可能な方法でメモリ割り当てアルゴリズムと相互作用したのは運が良かっただけです(削除されたFireは常に同じ方法で新しいFireで上書きされました)。そうでない場合、オンラインプレーヤー間で非同期が発生します。ゲームがメモリ割り当てを行う方法を書き直したときに、このバグを見つけました。その予測可能性のために、私がそれを修正したとき、私は古いゲームクライアントとの互換性のためにその動作のエミュレーションを実装することもできました。