Хорошо, мы поняли, что поведение не определено.Но давайте сделаем небольшое путешествие в то, что действительно происходит.Я использую VS 2008.
Вот мой код:
class Test
{
int i;
public:
Test() : i(3) { }
~Test()
{
if (!i)
return;
printf("%d", i);
i--;
Test::~Test();
}
};
int _tmain(int argc, _TCHAR* argv[])
{
delete new Test();
return 0;
}
Давайте запустим его и установим точку останова внутри деструктора, и пусть случится чудо рекурсии.
Вот трассировка стека:
альтернативный текст http://img638.imageshack.us/img638/8508/dest.png
Что это такое scalar deleting destructor
?Это то, что компилятор вставляет между delete и нашим реальным кодом.Сам по себе деструктор - это просто метод, в этом нет ничего особенного.Это действительно не освобождает память.Это выпущено где-то внутри этого scalar deleting destructor
.
Давайте перейдем к scalar deleting destructor
и рассмотрим разборку:
01341580 mov dword ptr [ebp-8],ecx
01341583 mov ecx,dword ptr [this]
01341586 call Test::~Test (134105Fh)
0134158B mov eax,dword ptr [ebp+8]
0134158E and eax,1
01341591 je Test::`scalar deleting destructor'+3Fh (134159Fh)
01341593 mov eax,dword ptr [this]
01341596 push eax
01341597 call operator delete (1341096h)
0134159C add esp,4
во время нашей рекурсии мы застряли по адресу 01341586
, и память фактически высвобождается только по адресу01341597
.
Заключение: В VS 2008, поскольку деструктор является просто методом, а весь код освобождения памяти вводится в среднюю функцию (scalar deleting destructor
), безопасно вызывать деструктор рекурсивно.Но все же это не очень хорошая идея, ИМО.
Редактировать : Хорошо, хорошо.Единственная идея этого ответа состояла в том, чтобы взглянуть на то, что происходит, когда вы вызываете деструктор рекурсивно.Но не делайте этого, это вообще небезопасно.