Custom memory management
-
Have a look at this code snippet. You can compile it in VS2010 if you create a Qt4 project to put it in:
@#define WIN32_LEAN_AND_MEAN
#include <windows.h>#include <QtCore/QObject>
#include <QtCore/QList>
#include <QtCore/QVariant>static int mem_guid()
{
return 1;
}void* __cdecl operator new(size_t size)
{
int* real_mem = (int*)::malloc(size + sizeof(int));
*real_mem++ = mem_guid();
return real_mem;
}void __cdecl operator delete(void* mem)
{
int* real_mem = (int*)mem;
real_mem--;
::free(real_mem);
}int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
{ // success :)
QObject parent(0);
QObject* child = new QObject(&parent);
}
{ // failure :(
QVariant variant1(1);
QVariant variant2;
QList<QVariant> list;
list.append(variant1);
variant2.setValue(list);
}
return 0;
}@All our code uses a custom memory manager, through overloading operator new and operator delete. This is presenting us with serious problems since QVariant has a non-virtual destructor.
Now, in the first scope, the overloaded operator new and operator delete are invoked. In the second scope, the operator delete that QtCore4.dll is bound against is invoked, in my case the one supplied by the MS C++ run-time. This is because QList<QVariant> has already been partially instantiated in QtCore4.dll, including a call to operator delete. Since QVariant has no virtual destructor, the call is bound statically at link time, and the operator delete call is fully resolved to the run-time library. If QVariant's destructor were virtual the delete call would be deferred to runtime. In this case, where the scope lies in another module, the local operator delete is called rather than the one bound to QtCore4.dll.
There are three solutions:
- Rebuild Qt and link it to my operator new/delete functions.
- Make ~QVariant() virtual.
- Create a Qt client DLL and make calls in to it rather than host the Qt calls in our code.
I’m guessing option 3 is the safest, if the most ugly. Any other thoughts?