The SolutionFrom previous observations, the solution should be simple - just have the engine create and destroy all of its components. However, this is a much more complicated task than it sounds like. Let's look what I've done to make my engine totally self-reliant. The first thing that you need to do is to make every single constructor and destructor of every major engine element protected or private. At first, that sounds ridiculous. If the constructor and destructor are protected or private, nothing could create or destroy the object but itself! That is not entirely true. Those of you familiar with design patterns may recognize this technique from the Singleton design pattern. In the Singleton design pattern, the constructor is made private and it is called from a static member function. So, our engine components could be created from static creation methods. However, there is another way to access private and protected constructors and destructors. It is through friend classes. So, the second thing you need to do is define the following macro: #define CREATOR(p) friend class p Now, go through each one of your engine components (sounds, meshes, objects of any sort) and put a CREATOR into their class declarations. For instance, my Sound object now looks like: class Cb3dSound { CREATOR(Cb3dSoundSystem); protected: Cb3dSound(); Cb3dSound(LPSTR pFname); virtual ~Cb3dSound(); . . . }; Since the Sound class has declared that the SoundSystem class is its friend, the SoundSystem can create sounds. Along those same lines, my engine class can create my Keyboard, Mouse, Joystick, Mesh, and MeshObject classes. More importantly, my engine class MUST destroy those same objects. I will no longer be able to accidentally create an object that will not get destroyed at the proper time. And no longer will the debugger quietly tell me that I have leaked memory. It will give me a full-blown error if the objects are not deleted by the time the program ends, because those destructors are private and can not be called except by the object's CREATOR. In order to implement this fully, of course, more work is needed. First and foremost, you need to write creator functions for each constructor that you made private. For instance, my Engine class has the creator functions CreateMilkshapeMesh, Create3DSMesh, CreateMeshObject, CreateVertexBuffer, CreateIndexBuffer, and numerous others. Also, you need to store a linked list of all the pointers created by the engine. For instance, my engine class stores a list of all the meshes it creates, and then in the engine's destructor I destroy them all in turn, and in the correct order (i.e. before Direct3D is released). One important thing to remember is that not every class needs to have a CREATOR. For instance, it is absurd to make the Engine's constructor and destructor private, because all programs using it will manually create it. ConclusionDraw your own conclusions ;-) Well, let me tell you how it went. I implemented all of the changes I outlined above. I could swear that the actual lines of code that ran were exactly the same with or without the above changes. That is, I could swear that every object was getting created and destroyed in exactly the same order. But despite whatever I thought, I now get absolutely zero memory leaks. Questions? Comments? Complaints? Hate mail? Email me at benbeandogdilts@yahoo.com.
|