私の最初の基本的なテストでは、そうすることは完全に安全です。ただし、this
関数内で後で操作しようとdelete
するthis
と、実行時エラーになる可能性があることに気付きました。これは本当で、通常は安全delete this
ですか? それとも安全な特定のケースだけですか?
10 に答える
delete this
合法であり、期待どおりのことを行います。クラスのデストラクタを呼び出し、基になるメモリを解放します。delete this
返された後、this
ポインターの値は変更されないため、逆参照してはならないダングリング ポインターになります。これには、クラスのメンバー変数を使用した暗黙的な逆参照が含まれます。
通常、参照カウント クラスでは、ref-count が 0 にデクリメントされると // DecrementRefCount()
whateverRelease()
メンバー関数が呼び出しますdelete this
。
delete this
通常、多くの理由から非常に悪い形式と見なされます。の後で誤ってメンバー変数にアクセスするのは簡単ですdelete this
。呼び出し元のコードは、オブジェクトが自己破壊されたことを認識していない可能性があります。
また、delete this
コードがオブジェクトの所有権 (誰が割り当て、誰が削除するか) について対称的な戦略を持っていない可能性があるという「コードの匂い」です。オブジェクトは で自分自身を割り当てることができなかったnew
ので、呼び出しdelete this
は、クラス A がオブジェクトを割り当てていることを意味しますが、クラス B は後でそれを解放しています [self]。
基本的にメソッドの最後の操作である限り、「this」を削除しても安全です。実際、いくつかのプロフェッショナル レベルの API がそうしています (例については、ATL の CComObject 実装を参照してください)。
唯一の危険は、「delete this」を呼び出した後に他のメンバー データにアクセスしようとすることです。これは確かに安全ではありません。
しかし、デストラクタでそれをしないでください!
他の人がすでに述べたように、これは完全に合法です。まだ言及されていないもう1つの理由で危険です-オブジェクトがヒープに割り当てられていると想定しています。これを保証するのは難しい場合がありますが、参照カウントの実装の場合、一般的には問題になりません。
他の人が述べたように、これは有効なイディオムですが、安全であるためには、オブジェクトがスタック上でインスタンス化されないようにする必要があります。
これを行う 1 つの方法は、コンストラクターとデストラクターの両方をプライベートにし、クラス ファクトリ関数を使用してオブジェクトの作成を強制することです。この関数は、ヒープ上にオブジェクトを作成し、それへのポインターを返します。クラス ファクトリは、静的メンバー関数またはフレンド関数にすることができます。その後、「これを削除」するオブジェクトの Delete() メソッドを使用してクリーンアップを行うことができます。COM オブジェクトは基本的にこのように動作しますが、参照カウントが 0 にデクリメントされると「delete this」が発生して参照カウントされる点が異なります。
はい。それは完全に問題ないはずです。「これ」は単なるポインタです。任意のポインタで削除できます。オブジェクトの削除方法に関する情報は、ヒープ レコードに含まれています。これは、IUnknown::Release() が通常 COM オブジェクトに実装される方法です。
これは、削除するオブジェクトのサブクラスがある場合に問題を引き起こす可能性があります。構築は上から始まり、削除は下から始まることを忘れないでください。したがって、階層の中間にあるこれを削除すると、基本的に、この特定のクラスの下にあるすべてのオブジェクトが失われます。
これは、COM クラスなどの参照カウント オブジェクトを実装する場合に非常に便利です。
同様の議論を読んでください。後でこれにアクセスできないため、機能し、必要であり、危険である可能性があるという点で、あなたの理解は正しいです。
法的 はい
安全 いいえ
基本クラスから継承し、基本クラス関数でこれを削除した場合、派生クラス ポインターを使用するとクラッシュが発生します。例えば:
class Base
{
virtual void Release()
{
delete this;
}
}
class Derived : public Base
{
void Foo()
{
...
}
}
main()
{
Base *ptrDerived = new Derived();
ptrDerived->release();
ptrDerived->Foo() //Crash
}