28

今日、いくつかのレガシー コードを見てきました。デストラクタには " " のような文がありdelete thisます。この呼び出しは再帰的だと思います。なぜ機能しているのですか?

Y! を簡単に検索したところ、ユーザーがスタック オブジェクトを作成することを制限する必要がある場合は、デストラクタを非公開にし、インスタンスを削除するためのインターフェイスを提供できることがわかりました。提供されたインターフェイスでは、このポインターで delete を呼び出す必要があります。

そのようなステートメントを使用する他の状況はありますか?

4

4 に答える 4

32

「これを削除」は、参照カウントされたオブジェクトによく使用されます。ref カウントされたオブジェクトの場合、いつ削除するかの決定は通常、オブジェクト自体に委ねられます。以下は、Release メソッドがどのように見えるかの例です [1]。

int MyRefCountedObject::Release() {
  _refCount--;
  if ( 0 == _refCount ) {
    delete this;
    return 0;
  }
  return _refCount;
}

ATL COM オブジェクトは、このパターンの代表的な例です。

[1] はい、これはスレッドセーフではないことを認識しています。

于 2009-01-15T16:16:04.123 に答える
24

delete thisデストラクタでは無効です。他の場所で使用できます。しかし、それが良い考えであることはめったにありません。wxWidgetsフレームワークはそれをスレッド クラスに使用します。スレッドが実行を終了すると、システム リソースとそれ自体 (wxThread オブジェクト) を自動的に解放するモードがあります。オブジェクトが存在しないため、外部から参照することが有効かどうかを知ることができないため、非常に面倒IsValidでした。オブジェクトが存在しないため、関数を呼び出すことはできません。delete this非動的オブジェクトには使用できないという問題を除けば、これが の主な問題のようです。

それを行う場合は、データメンバーに触れたり、削除したオブジェクトでメンバー関数を呼び出したりしないようにしてください。非仮想、保護、またはプライベート関数の最後のステートメントとして実行することをお勧めします。delete の呼び出しは、仮想および/またはパブリック関数でも有効ですが、それを行うメソッドの可視性を制限します。

C++ FAQには、それに関するエントリがあります。上記の私の主張に関する C++ 標準の引用 ( 3.8p5):

オブジェクトの有効期間が開始する前であるが、オブジェクトが占有するストレージが割り当てられた後、またはオブジェクトの有効期間が終了した後、オブジェクトが占有していたストレージが再利用または解放される前に、ストレージを参照するポインターオブジェクトが配置される、または配置された場所を使用できますが、限られた方法でのみ使用できます。[...]オブジェクトが非自明なデストラクタを持つクラス型になるか、そうであった場合、ポインタが削除式のオペランドとして使用されると、プログラムは未定義の動作をします。

オブジェクトのデストラクタが実行を開始すると、ライフタイムは終了します。このパラグラフの後に続く、構築中および破棄中のオブジェクトに関する規則には例外があることに注意してください (たとえば、非静的データ メンバーへのアクセスが許可されます)。詳しくは、 を参照して12.7ください。

于 2009-01-15T16:44:55.627 に答える
3

初期の C++ 時代にこれを行う正当な理由があると考えられている場所があります。たとえば、refカウントされたオブジェクトの自己削除(JaredParが言うように)。私の知る限り、それらはすべて長期的には悪い考えであることがわかっています。

于 2009-01-15T17:06:34.427 に答える
2

双方向にリンクされたリストでは、高レベルの「リスト」オブジェクトなどの外部構造を参照せずにノードを削除できます。これにより、各ノードが独自の割り当て解除を処理することが合理的になります (潜在的に、同じメモリ プールからの初期割り当てを処理するための補完的な静的メソッドと結合されます)。この状況では、ノード オブジェクトがそれ自体を削除することが理にかなっている場合があります (ユーザーが要求した場合)。

void RemoveAndDeallocate()
{
    LinkedListNode *current_prev = prev, *current_next = next;
    current_prev->next = current_next;
    current_next->prev = current_prev;
    delete this;
}

ただし、メモリの割り当てを解除せずに、ノードをあるリストからリンク解除して別のリストにリンクすることも合理的であるため、1 回の削除操作で無条件にメモリを解放することは望ましくありません。

于 2010-01-30T02:20:19.723 に答える