Search code examples
c++garbage-collectionobjectfactory

Game Object Factory: Fixing Memory Leaks


Dear all, this is going to be tough: I have created a game object factory that generates objects of my wish. However, I get memory leaks which I can not fix.

Memory leaks are generated by return new Object(); in the bottom part of the code sample.

static BaseObject * CreateObjectFunc()
{
    return new Object();
}

How and where to delete the pointers? I wrote bool ReleaseClassType(). Despite the factory works well, ReleaseClassType() does not fix memory leaks.

bool ReleaseClassTypes()
{
    unsigned int nRecordCount = vFactories.size();
    for (unsigned int nLoop = 0; nLoop < nRecordCount; nLoop++ )
    {
        // if the object exists in the container and is valid, then render it
        if( vFactories[nLoop] != NULL) 
            delete vFactories[nLoop]();
    }
    return true;
}

Before taking a look at the code below, let me help you in that my CGameObjectFactory creates pointers to functions creating particular object type. The pointers are stored within vFactories vector container.

I have chosen this way because I parse an object map file. I have object type IDs (integer values) which I need to translate them into real objects. Because I have over 100 different object data types, I wished to avoid continuously traversing very long Switch() statement.

Therefore, to create an object, I call vFactories'['nEnumObjectTypeID']'() via CGameObjectFactory::create() to call stored function that generates desired object.

The position of the appropriate function in the vFactories is identical to the nObjectTypeID, so I can use indexing to access the function.

So the question remains, how to proceed with garbage collection and avoid reported memory leaks?

#ifndef GAMEOBJECTFACTORY_H_UNIPIXELS
#define GAMEOBJECTFACTORY_H_UNIPIXELS

//#include "MemoryManager.h"
#include <vector>


template <typename BaseObject>
class CGameObjectFactory
{
public:
    // cleanup and release registered object data types
    bool ReleaseClassTypes()
    {
        unsigned int nRecordCount = vFactories.size();
        for (unsigned int nLoop = 0; nLoop < nRecordCount; nLoop++ )
        {
            // if the object exists in the container and is valid, then render it
            if( vFactories[nLoop] != NULL) 
                delete vFactories[nLoop]();
        }
        return true;
    }

    // register new object data type
    template <typename Object>
    bool RegisterClassType(unsigned int nObjectIDParam )
    {
        if(vFactories.size() < nObjectIDParam) vFactories.resize(nObjectIDParam);

        vFactories[nObjectIDParam] = &CreateObjectFunc<Object>;
        return true;
    }


    // create new object by calling the pointer to the appropriate type function
    BaseObject* create(unsigned int nObjectIDParam) const
    {
        return vFactories[nObjectIDParam]();
    }


    // resize the vector array containing pointers to function calls
    bool resize(unsigned int nSizeParam)
    {
        vFactories.resize(nSizeParam);
        return true;
    }

private:
    //DECLARE_HEAP;

    template <typename Object>
    static BaseObject * CreateObjectFunc()
    {
        return new Object();
    }


    typedef BaseObject*(*factory)();
    std::vector<factory> vFactories;
};


//DEFINE_HEAP_T(CGameObjectFactory, "Game Object Factory");

#endif // GAMEOBJECTFACTORY_H_UNIPIXELS

Solution

  • You can start by using std::shared_ptr or std::tr1::shared_ptr or boost::shared_ptr depending on your compiler.

    You would use it like this:

    typedef std::shared_ptr<BaseObject> BaseObjectPtr;
    static BaseObjectPtr CreateObjectFunc()
    {
        return BaseObjectPtr(new Object());
    }
    

    You won't need to release the created resources. They will do automatic reference counting and deallocate themselves when there are no strong references pointing to it.

    So in your second code example:

    #ifndef GAMEOBJECTFACTORY_H_UNIPIXELS
    #define GAMEOBJECTFACTORY_H_UNIPIXELS
    
    //#include "MemoryManager.h"
    #include <vector>
    #include <memory>
    
    template <typename BaseObject>
    class CGameObjectFactory
    {
    public:
        typedef std::shared_ptr<BaseObject> BaseObjectPtr;
    
        // cleanup and release registered object data types
        bool ReleaseClassTypes()
        {
            unsigned int nRecordCount = vFactories.size();
            for (unsigned int nLoop = 0; nLoop < nRecordCount; nLoop++ )
            {
                // if the object exists in the container and is valid, then render it
                //if( vFactories[nLoop] != NULL) 
                //    delete vFactories[nLoop]();
                // The above code would create something then immediately delete it.
                // You could keep a container of pointers to the objects you created
                // and loop through that instead, or use shared_ptr.
                // If you want to unregister the creator functions just NULL the pointer.
                vFactories[nLoop] = NULL;
            }
            return true;
        }
    
        // register new object data type
        template <typename Object>
        bool RegisterClassType(unsigned int nObjectIDParam )
        {
            if(vFactories.size() < nObjectIDParam) vFactories.resize(nObjectIDParam);
    
            // Store a pointer to the creation function
            vFactories[nObjectIDParam] = &CreateObjectFunc<Object>;
            return true;
        }
    
    
        // create new object by calling the pointer to the appropriate type function
        BaseObjectPtr create(unsigned int nObjectIDParam) const
        {
            return vFactories[nObjectIDParam]();
        }
    
    
        // resize the vector array containing pointers to function calls
        bool resize(unsigned int nSizeParam)
        {
            vFactories.resize(nSizeParam);
            return true;
        }
    
    private:
        //DECLARE_HEAP;
    
        template <typename Object>
        static BaseObjectPtr CreateObjectFunc()
        {
            return BaseObjectPtr(new Object());
        }
    
    
        typedef BaseObjectPtr(*factory)();
        std::vector<factory> vFactories;
    };
    
    
    //DEFINE_HEAP_T(CGameObjectFactory, "Game Object Factory");
    
    #endif // GAMEOBJECTFACTORY_H_UNIPIXELS
    

    See if that helps.