The joy of virtual destructors

A few weeks back I was in the middle of an ugly bug around loading wave files from memory. During that whole thing I found a number of bugs in my engine that didn't solve the problem but were bugs none the less. The most interesting was the fact that I forgot to make a number of my base classes have virtual destructors. This can lead to bad and weird stuff.

The basic gist is that any time you have a class with virtual functions you usually have virtual functions because you want to refer to an object using a pointer of its base type. So if you have a base class called say CCar, you might have other classes derived from it, like CSportsCar or CSedan, but want to refer to them all as CCar. This is an easy way to say keep all cars together in one container like an array.

Where this runs into trouble is when you delete an object by refering to its base class. A little example:

void Func(){ CCar *Temp; CSportsCar *Car1; CSedan *Car2;

Car1 = new CSportsCar(); Car2 = new CSedan();

Temp = (CCar*)Car2;

delete Car1;delete Temp;}

In the above example when I delete Car1 its destructor gets called properly because the pointer is of type CSportsCar. But when I delete Temp, which is the same address as Car2, the only destructor that gets called is that of the base class CCar. That means any work in the CSedan destructor, ie. freeing resources, never gets called. That means memory leaks or worse.

So why am I rehashing this all now if I found out about this bug weeks ago? Well I was so into my wave loading problem that I forgot to fix this problem with all of my classes. This problem reared its ugly head in my texture objects which weren't properly releasing themselves and thereby keeping me from releasing my D3D device. I ran into this when I was making my game remember its fullscreen/windowed state between sessions.

Somehow when you start up in windowed mode in D3D8 it was letting me release the D3DDevice without letting go of my textures, not expected behaviour. But this meant that when I started up in windowed mode first I could switch between windowed and fullscreen easily as many times as I wanted to. But when I started up in fullscreen mode I couldn't switch to windowed mode at all. Weird.

Anyway making all of my base objects have virtual destructors fixed the problem and I'm now releasing all my resources like a good coder should. A good rule of thumb lesson to take from this problem:

Any time you have a class with a virtual method make sure the destructor is virtual too.

If I was a hard core C++ dev I wouldn't have to remind myself of these things. But such are the perils of taking a desk job where you write docs more than code. :)