2016-05-25 17 views
0
#include <iostream> 

struct ABC{ 
    int A; 
    ABC(int i = 1) : A(i) {} 
    ~ABC() { 
     std::cout << A << std::endl; 
    } 
    void destruct() { 
     delete this; 
    } 
}; 

int main() { 
    ABC A1(2); 
    A1.destruct(); 
    return 0; 
} 

Output: 
2 
2 

私は構造変数を手動で削除しようとしているこのコードを持っています。そうすることで、デストラクタがここで2回呼び出されることに気付きました。なぜこうなった? destruct()を呼び出すと、なぜそれが削除されないのですか?デストラクタがここで2回呼び出されるのはなぜですか?

+2

「新しい」ではないものを「削除」しない –

答えて

6

delete thisコールの原因となるのはundefined behaviourなので、何かが起こる可能性があります。

deleteは、newで作成されたオブジェクトに対してのみ使用できます。非自明なデストラクタ(例えば、あなたのA1)と自動オブジェクトの場合


、スコープが終了する前にも同じ場所で別のABCを作成しない限り、「早期それらを破壊」することはできません。つまり、スコープが終了したときに発生する破壊プロセスを「停止」することはできません。

+0

自動オブジェクトが早期にスコープから外れるように強制することで、自動オブジェクトの早期破壊を引き起こすことができます。自動オブジェクトを宣言し、初期化し、{}で使用するコードブロックをラップすることで、これを行うことができます。しかし、最適化コンパイラが後で破壊を遅らせることができないかどうかはわかりません。 –

+0

@ P.Kouvarakisは「早期」に「私の範囲の終わりの前に」という意味です。 –

+0

はい、私はそれを理解しており、私たちはどちらも同意したと思います。私はあなたが思っているよりも早く範囲を終了できるかもしれないことを指摘していました。多くの人々は{}を使ってループや関数などのコードブロックを定義し、可変スコープを定義するためにそのコードブロックを使用できることを忘れてしまいがちです。 –

2

これはRAIIの作業であり、オブジェクトに対して自殺しています。オブジェクト上でデストラクタを呼び出すことはほとんど常に間違っています!デストラクタを2回呼び出すことは、未定義の動作を引き起こすため、常に間違っています。

struct Foo{}; 
int main() { 
    Foo f;    // automatic storage, gets destroyed 
         // when object gets out of scope 

    Foo* g = new Foo(); // heap allocated 
    delete g;   // only here you have to delete 
} 

はただ覚えている:あなたはマイク・バインにnew(おかげ経由で作成していないではないdelete何かを

あなたは、あなたがそれを許可すればC++は、あなたのためのメモリを処理していることを理解する必要がありますコメント)。必要がない限り、(裸の)ヒープ割り当てを使用しないでください。

+0

'delete'はデストラクタを呼び出す*と*メモリを解放するという2つのことを行います。メモリを解放せずにデストラクタを呼び出すこともできます(メモリを解放する別の理由でUBにつながります) –

+0

@M M.それを指摘してくれてありがとう。私はちょっと単純すぎることを知っていた。 – user463035818

2

destruct()を呼び出すと、[my object]が削除されないのはなぜですか?

オブジェクトがC++で破壊されても、オブジェクトが消えてしまうわけではありません。これは、デストラクタからのクリーンアップコードが実行され、そのポイントからのオブジェクトのメンバへのアクセスがすべて無効であることを意味します。

destruct()に電話するときは、deleteを呼び出してオブジェクトのメモリを解放しようとします。 newでオブジェクトを割り当てていないため、これ自体は未定義の動作です。この呼び出しにより、最初の印刷が行われます。

ただし、オブジェクトが自動メモリにあるため、オブジェクトがスコープから外れると、C++はデストラクタを呼び出す必要があります。これは、2番目のプリントアウトを引き起こすコールです。

注:あなたが動的メモリにA1を割り当てることによって、あなたのコードを修正することができます

int main() { 
    ABC *A1 = new ABC(2); 
    A1->destruct(); 
    return 0; 
} 

今、あなたは、単一のプリントアウト(demo)を取得します。しかし、メンバー関数にdeleteを隠す習慣は疑わしい。ここで考慮すべき

+0

'delete this;'は自分自身を管理するオブジェクトのイディオムで使用されていますが、これを削除する必要はありません。参照カウント –

1

2点: -

1)彼らはスコープの外に行くときのスタックオブジェクトのデストラクタは、常に呼び出されます。そのため、割り当て解除を心配する必要はありません。

2)&は、スタックに割り当てられたオブジェクトに対してdeleteを使用しないでください。通常、ヒープオブジェクトの削除の結果としてのみ実行され、その後はそのオブジェクトを参照していないことが確実でない限り、delete thisを使用しないでください。

関連する問題