久々の「アリプラ」シリーズです(自分も忘れていたよ)。
void*にdeleteしてもデストラクタが呼ばれない!? – かずきのBlog@Hatena
http://d.hatena.ne.jp/okazuki/20120204/1328323854
というのを見つけて、一瞬「?」と思ったのですが、確かにそうですね。delete するときに void* を渡すと型情報が失われる…というか、delete が型情報を判別できないので、メモリとしか解放されなくてデストラクタが呼び出されません、という現象です。
配列を new したときに、「delete [] ポインタ」 で解放しないといけません。ってのと同じ話だと思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | #include <iostream> using namespace std; // アリスクラス class Alice { public : Alice() { cout << "in constractor" << endl; } ~Alice() { cout << "in destractor" << endl; } }; class Person { public : Person() { cout << "in Parson::Parson" << endl; } virtual ~Person() { cout << "in Parson::~Parson" << endl; } }; // ロリータクラスは、Person クラスを継承する class Lolita : public Person { public : Lolita() { cout << "in Lolita::Lolita" << endl; } virtual ~Lolita() { cout << "in Lolita::~Lolita" << endl; } }; // アリスはvoid*がお嫌い int main( int argc, char *argv[] ) { { cout << "自動で解放" << endl; Alice alice; } { cout << "自前で解放" << endl; Alice *alice = new Alice(); delete alice; } { cout << "void*で解放" << endl; void *alice = new Alice(); delete alice; } { cout << "継承あり" << endl; Lolita *lolita = new Lolita(); delete lolita; } { cout << "継承あり Person" << endl; Person *lolita = new Lolita(); delete lolita; } { cout << "継承あり void*" << endl; void *lolita = new Lolita(); delete lolita; } { cout << "継承あり void* から Lolita へキャスト" << endl; void *lolita = new Lolita(); delete (Lolita*)lolita; } { cout << "継承あり void* から Person へキャスト" << endl; void *lolita = new Lolita(); delete (Lolita*)lolita; } return 0; } /* 実行結果 D:\work\blog\src\alice>alice015 自動で解放 in constractor in destractor 自前で解放 in constractor in destractor void*で解放 in constractor 継承あり in Parson::Parson in Lolita::Lolita in Lolita::~Lolita in Parson::~Parson 継承あり Person in Parson::Parson in Lolita::Lolita in Lolita::~Lolita in Parson::~Parson 継承あり void* in Parson::Parson in Lolita::Lolita 継承あり void* から Lolita へキャスト in Parson::Parson in Lolita::Lolita in Lolita::~Lolita in Parson::~Parson 継承あり void* から Person へキャスト in Parson::Parson in Lolita::Lolita in Lolita::~Lolita in Parson::~Parson */ |
普通に void* のまま delete してしまうと、デストラクタが呼び出されませんが、delete 時に元の型(Lolita)に戻してやると、正常にデストラクタが呼び出されます。継承元の Person* に戻してもきちんと Lolita のデストラクタが呼び出されるのは、デストラクタが virtual になっているためです。