I've been looking at some of the assembly code output (full optimizations on) of VS2003 and VS2005 recently, and have found something bizarre with the way objects are created and destroyed.
Given the following simple, innocent-looking class:
#define MYINLINE __forceinline
class foo
{
public:
MYINLINE foo();
MYINLINE ~foo();
};
MYINLINE foo::foo()
{
}
MYINLINE foo::~foo()
{
}
One would expect any code which uses this object to simply not have any overhead with a constructor or destructor. Indeed, doing something as simple as:
void main(void)
{
foo f;
}
Results in the compiler completely optimizing away f, as it's not even being used. Even if class foo is actually expanded to do something useful, the constructor and destructor are empty and are never called. However, things get a little strange when an array of foos are allocated:
void main(void)
{
foo f[1024];
}
The compiled code gets turned into this evil mess:
void main(void)
{
00401020 sub esp,400h
foo f[1024];
00401026 push offset foo::~foo (401010h)
0040102B push offset foo::foo (401000h)
00401030 push 400h
00401035 push 1
00401037 lea eax,[esp+10h]
0040103B push eax
0040103C call `eh vector constructor iterator' (401121h)
}
00401041 push offset foo::~foo (401010h)
00401046 push 400h
0040104B push 1
0040104D lea ecx,[esp+0Ch]
00401051 push ecx
00401052 call `eh vector destructor iterator' (4010BEh)
00401057 xor eax,eax
00401059 add esp,400h
0040105F ret
Yuck! Both the constructors and destructor functions are being called for _each_ of the objects in the array (1024 times)! Interestingly, the use of __forceinline didn't even give
warning 4714.
Stepping into the constructor and destructor iterators is a loop which loads the 'this' pointer for the class and then calls into the actual ctor or dtor:
MYINLINE foo::foo()
{
00401000 mov eax,ecx
}
00401002 ret
MYINLINE foo::~foo()
{
}
00401010 ret
I then tried removing the destructor function body entirely, and finally the compiler optimized the prolog/epilog code away.
Is there anything "wrong" with not having a destructor for an object? In my case where there is no code in the destructor, is it actually better to not declare one in the first place?
Also, if anyone is willing, I'm curious to see how other compilers (gcc, Intel, etc) handle this situation.