私はいくつかのコードを書いたばかりで、オブジェクトがどのようにポリモーフィックに破壊されるかを理解しようとしています。
#include <iostream>
struct Base {
virtual ~Base() {
std::cout << "base destructed\n";
}
};
struct Derived : public Base{
virtual ~Derived() {
std::cout << "derived destructed\n";
}
};
int main() {
Derived der;
Base bases1[2], bases2[2], bases3[2], bases4[2];
//case 1
new(bases1) Derived(der);
std::cout << "((Base*)bases1)->~Base();\n";
((Base*)bases1)->~Base();
//case 2
new(bases2) Derived(der);
std::cout << "\nbases2->~Base();\n";
bases2->~Base();
//case 3
new(bases3) Derived(der);
std::cout << "\nbases3[0].~Base();\n";
bases3[0].~Base();
//case 4
new(bases4) Derived(der);
std::cout << "\n(*bases4).~Base();\n";
(*bases4).~Base();
getchar();
return 0;
}
上記のコードについて私が知っていること:
- ケース 1 では、bases1 は Derived オブジェクト (vptr を含む) の先頭を指し、これはベース ポインターであるため、ベース ポインターで削除する通常のケースと同じです (つまり、破棄)。
- ケース 2 では、bases2 は配列名ですが、場合によっては最初のオブジェクトを指すポインターとして扱うことができるので、ケース 2 はケース 1 と同じ結果になるはずですか?
- ケース 3 とケース 4 は同じです。どちらも、タイプが Base の最初のオブジェクトを逆参照してから、そのデストラクタを呼び出します。
- これらのコードは非標準で危険ですが、特定のコンパイラ (Visual Studio 2012) でどのように機能するかを知りたいだけです。
出力:
((Base*)bases1)->~Base();
derived destructed
base destructed
bases2->~Base();
bases3[0].~Base();
base destructed
(*bases4).~Base();
base destructed
私が知りたいこと:
- ケース 2 では、何も破壊されません。考えられる理由は何ですか? コンパイラの最適化?
- ケース 3 とケース 4 では、ベースのみが破壊されますが、なぜですか? オブジェクトのスライス?
編集:
以下は、[逆アセンブリ] ウィンドウから取得したものです。
((Base*)bases1)->~Base();
00D96CF9 mov esi,esp
00D96CFB push 0
00D96CFD mov eax,dword ptr [bases1]
00D96D00 lea ecx,[bases1]
00D96D03 mov edx,dword ptr [eax]
00D96D05 call edx
00D96D07 cmp esi,esp
00D96D09 call __RTC_CheckEsp (0D91992h)
bases2->~Base(); //empty
bases3[0].~Base();
00D96DB0 push 0
00D96DB2 mov eax,4
00D96DB7 imul eax,eax,0
00D96DBA lea ecx,bases3[eax]
00D96DBE call Base::`vector deleting destructor' (0D91A0Ah) //array delete?
(*bases4).~Base();
00D96E14 push 0
00D96E16 mov eax,4
00D96E1B imul eax,eax,0
00D96E1E lea ecx,bases4[eax]
00D96E22 call Base::`vector deleting destructor' (0D91A0Ah) //aray delete?
アセンブラが読めないのですが、どなたか合理的な説明をいただけないでしょうか?