ノードがループを形成しているポインターを考慮するとmNext
、ノードのいずれかを破壊すると、おそらく無限再帰ループが形成され、スタックを爆破してプログラムが終了します。
起こりそうなことは
- 最初の「外部」
delete node;
が発行されます。
- ノード デストラクタに入るときは、コード デストラクタが破棄プロセスで実行される「最初の」処理であるため、まだ何も実行されていません (破棄プロセス自体は非常に複雑で、デストラクタ コード、クラス変更、メンバーの破棄、ベースの破棄がこの順序で含まれます。詳細な説明については、この回答を参照してください)。
- 最初のデストラクタ命令が実行
delete mNext;
され、ループ内の次のノードで同じプロセスがトリガーされます。
- ノードがループを形成しているため、このチェーンは
node
「後ろから」再び到達するため、最初の呼び出しが決して終了しない再帰になります。
- いずれにせよ、呼び出しごとにアクティベーション レコードにスタック スペースが割り当てられるため、しばらくすると、スタックに使用できるすべてのメモリが使い果たされ、OS がプロセスを強制終了します。デストラクタ コードが完了した後、メモリの割り当てを解除する必要があるため、削除呼び出しは「テール コール」ではありません。この再帰を簡単に最適化することはできません
delete mNext;
。delete
オペレーターが完了します。
ただし、私の経験では、特別なコンパイラ オプションを使用しない限り、スタック オーバーフローはチェックされないため、プログラムの終了は非常に「異常」になることに注意してください。また、Windows では、プログラムの終了時に segfault エラーが発生した場合にそれを隠す恐ろしいコードがいくつかあることに注意してください。そのため、イベント ループを終了した後にこの操作が行われると、Windows プログラムが明らかに正常に終了する可能性が十分にあります。
スタック オーバーフローは通常は考慮されないため、明らかな「無限ループ」を含むあらゆる動作が可能です (この無限ループは再帰的デストラクタのものではなく、ランタイム システム内のどこかがスタック オーバーフローのために狂っている可能性があることに注意してください)。 .
なぜ私はおそらくという言葉を使ったのですか?その理由は、C++ 標準では、オブジェクトの複数の破壊は未定義の動作であると述べているためです。C++ では破壊を完了せずにデストラクタを終了する方法がないという事実にこれを追加すると、コンパイラは理論上、オブジェクトに「破壊されている」というフラグを立て、デーモンをオブジェクトから飛ばすことが許可されていることを理解できます。同じオブジェクトのデストラクタを 2 回入力すると、nosrils が発生します。ただし、このエラーのチェックは必須ではなく、コンパイラの作成者は怠け者であることが多く (これはプログラマにとって侮辱ではありません)、したがって、このチェックが存在する可能性は低いです (特別な追加のデバッグ オプションが有効になっている場合を除く)。
要約すると、永久にループできますか? はい。クラッシュできますか?もちろん。オブジェクトが 2 回破棄されているというメッセージを止めることはできますか? もちろん。プログラムを正常に終了できますか (つまり、エラー コードを設定せずに)?はい、それも。
何でも起れる。そしてマーフィーは、あなたに最も大きな損害を与えるものは何でも起こると言っています...たとえば、プログラムは開発中に毎回正常に終了します...そして、デモの日に直面するとひどくクラッシュします.千人の見込み客の前で。
それをしないでください:-)