Your new() is not my new()

One of the problems I’ve experienced using third-party DLLs is the way that they handle new and delete for C++ classes, which can lead to memory leaks or even memory corruption. This was a particular problem when developing the Guild Wars model and animation exporter for 3ds Max, since 3ds Max uses plugins extensively, many written by different teams without the same coding standards as the original authors.
Here’s an example class API defined in a header file:
// FoozleDll.h
class CFoozle { ... };
CFoozle * MakeFoozle (CBarzle * bar);
And the associated CPP file:
// FoozleDll.cpp
CFoozle * MakeFoozle (CBarzle * bar) {
return new CFoozle(bar);
}
In the application code we’re supposed to create and later delete this object, so here goes:
// Main.cpp
void ProcessData (CBarzle * bar, iostream * outfile) {
CFoozle * foo = MakeFoozle(bar);
foo->WriteResults(outfile);
delete foo;
}
That all looks pretty straightforward, but what isn’t immediately obvious is that the call to new() is made in the context of the Foozle DLL file, and the delete() call is done in the context of the application, which might be using an entirely different memory manager.
Since the DLL was compiled separately, it might link to the release version of the C runtime library, where new() calls malloc() behind the scenes. But the call to delete() occurs in the application code, which could link to the Debug library, which calls _free_dbg() instead of free(). When the application releases the memory via the call to delete it is calling the wrong memory manager, which leads to problems like the inability of the application to coalesce adjacent free memory blocks (memory leakage) or random memory corruption.
The correct solution is that a module which allocates an object should also free the object:
// FoozleDll.h
class CFoozle {
public:
...
// This function must not be implemented in the header or the
// linker will build the code to call the application delete()
// function instead of the library delete() function.
void DeleteThis ();
private:
~CFoozle (); // private so it can only be called by DeleteThis();
};
And the implementation:
// FoozleDll.cpp
void CFoozle::DeleteThis () {
delete this; // called from the right "delete context"
}
By calling delete() from within the same compilation unit, we can ensure that the compiler will generate a call to the correct delete function.
Incidentally, this same type of problem can occur in C, where a DLL function returns (for example), the result of strdup(), and the application is expected to call free() on the resulting string.
C++: so powerful, so easy to break things.