Is this program well-defined, and if not, why exactly?
#include
#include
struct X {
int cnt;
X (int i) : cnt(i) {}
~X()
Okay, we understood that behavior is not defined. But let's do small journey into what really happends. I use VS 2008.
Here is my code:
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;
}
Let's run it and set a breakpoint inside destructor and let the miracle of recursion happen.
Here is stack trace:
What is that scalar deleting destructor
? It is something that compiler inserts between delete and our actual code. Destructor itself is just a method, there is nothing special about it. It doesn't really release the memory. It is released somewhere inside that scalar deleting destructor
.
Let's go to scalar deleting destructor
and take a look at the disassembly:
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
while doing our recursion we are stuck at address 01341586
, and memory is actually released only at address 01341597
.
Conclusion: In VS 2008, since destructor is just a method and all memory release code are injected into middle function (scalar deleting destructor
) it is safe to call destructor recursively. But still it is not good idea, IMO.
Edit: Ok, ok. The only idea of this answer was to take a look at what is going on when you call destructor recursively. But don't do it, it is not safe generally.