2017-02-22 9 views
0

ちょっと好奇心から私はコンパイラがスタックオーバーフローで終わる無限ループを呼び出すのではなく警告を出すかどうかを調べるために、以下のようなことをしようとしました。私は、通常の関数やメソッドを呼び出すのとは異なる振る舞いがあるかもしれないと考えました。しかし、そうではありません。私は明示的に基本クラスのデストラクタを呼び出してthis演算子を使用しているので、特別な説明はありますか、通常の関数呼び出しとして処理されているだけですか?コンパイラは、派生デストラクタで基本クラスのデストラクタ呼び出しをどのように処理しますか?

例:M.Mさんのコメント@

class A { 
    virtual ~A(); 
}; 

class B : A { 
    virtual ~B() { this->~A(); } 
}; 
+2

'virtual void〜A();' - これはコンパイルしないでください。デストラクタは何も返さず、通常のメソッド名にはtildaを含めることはできません。 – yeputons

+0

@yeputons right、sry、typo –

+4

'〜A()'を2回呼び出すと未定義の動作が発生します( 'B()'の本体が終了した時点で暗黙の呼び出しがあるので) –

答えて

2

はそれをヒット。あなたはデストラクタを2回呼びます。これは未定義の動作であり、観察される動作を含む何らかの事態が発生する可能性があります。

(実際には、最も可能性の高いこれらのデストラクタの呼び出しのいずれかが、その後のデストラクタは、ほとんどの派生オブジェクトに行くもはや呼び出すことを意味しない、オブジェクトのvptrを変更します。しかし、それはただの推測です。)

正しい事デストラクタを手動で呼び出さないことです。

+1

C++ 14 [class.dtor]/15 '' virtual''が自明ではないので、これは非自明なデストラクタを持つクラスに対して、特に2番目のデストラクタ呼び出しがUBであると言う節です。 –

0

派生クラスの仮想デストラクタを呼び出すと、基本クラスのデストラクタが呼び出されます。しかし、その逆ではありません。

1

派生クラスの仮想デストラクタは、親クラスのデストラクタを最初に呼び出します。再帰的な順序で、最も「祖先」のベースクラスのデストラクタが呼び出され、次に2番目の「祖先」子供がGrandParentから継承した親から継承すると想像してください。 Childクラスのデストラクタは実際にGrandParentのデストラクタを呼び出し、次にParentのデストラクタを呼び出し、次にChildのデストラクタを呼び出します。

実際、派生クラスのコンストラクタも、同じ再帰的順序で親クラスのコンストラクタを呼び出します。あなたは "レイヤーケーキ"のような派生クラスを想像しなければなりません:継承の各インスタンスはオブジェクトにレイヤーを追加します。そのため、Childクラスには3つのレイヤ{GrandParent、Parent、Child}があり、各レイヤの構築/破棄は対応するクラスによって処理されます。

あなたがしようとしているのは、親デストラクタを2回呼び出すことです。これは悪い考えです。一般的に、デストラクタを明示的に呼び出す必要はありません。ただし、new演算子をオーバーロードした場合を除きます。 Is calling destructor manually always a sign of bad design?

関連する問題