Hi there,

I've written a very basic dynamic memory allocation class which ensures that any dynamically allocated memory is automatically deallocated when the program ends, essentially providing a basic garbage collection feature. The class uses a simple structure to keep track of all the memory that is allocated and again uses this when deallocating memory (either manually or automatically at the program's end). The only problem is that sometimes the tracker will record duplicate entries for the same block of memory, meaning that when a particular block of memory is freed, if the tracker has duplicate entries then it will inevitably try to free the same block of memory twice, thus causing the program to crash. I've tried several things to get around this but cannot work out specifically what is causing the problem. The code I've got is below:

Code:
// memorg.h

struct MEMORYTRACKER
{
    void *MemBlock;             // All-purpose pointer to the block of T objects
    bool Allocated;             // Whether this block has yet been allocated
    unsigned long NumObjects;   // The number of T objects allocated in this block
};

class DLLIMPORT MEMORY
{
public:
    MEMORY();
    ~MEMORY();
    template <typename T> inline T *Allocate(unsigned long);
    template <typename T> inline T *Resize(T *, unsigned long);
    template <typename T> inline void Deallocate(T *);
private:
    MEMORYTRACKER *MT;
    unsigned long NumMemBlocks;
};

template <typename T>
T *MEMORY::Allocate(unsigned long Num)
{
    T *MemBlock, *NewMem;

    NumMemBlocks++;

    MT = (MEMORYTRACKER *) realloc(MT, NumMemBlocks * sizeof(MEMORYTRACKER));
    
    // This ensures that the T objects are constructed properly..
    NewMem = new T[Num];
    
    // ..while this allows us to use realloc later on if need be
    MemBlock = (T *) malloc(Num * sizeof(T));
    
    // We copy the constructed T objects into the space allocated by malloc..
    memcpy(MemBlock, NewMem, Num * sizeof(T));
    
    // ..then delete the temporary memory allocated with new
    delete [] NewMem;
    
    MT[NumMemBlocks - 1].MemBlock = MemBlock;
    MT[NumMemBlocks - 1].Allocated = true;
    MT[NumMemBlocks - 1].NumObjects = Num;
    
    return MemBlock;
}

template <typename T>
T *MEMORY::Resize(T *MemBlock, unsigned long Num)
{
    unsigned long i;
    unsigned long MemBlockNum;
    bool MemBlockFound = false;
    
    for(i = 0; i < NumMemBlocks; i++)
    {
        if(MT[i].MemBlock == MemBlock)
        {
            MemBlockNum = i;
            MemBlockFound = true;
        }
        
        if(MemBlockFound)
        {
            break;
        }
    }
    
    if(MemBlockFound)
    {
        MemBlock = (T *) realloc(MemBlock, Num * sizeof(T));

        if(MT[MemBlockNum].NumObjects < Num)
        {
            // We're resizing the memory block to a larger size than previously, so whatever the
            // size difference is, we use new to allocate the extra T objects so that they will
            // be properly constructed, while the existing data remains unchanged
            unsigned long NumObjects = Num - MT[MemBlockNum].NumObjects;
            
            T *NewMem = new T[NumObjects];
            
            memcpy(MemBlock + MT[MemBlockNum].NumObjects, NewMem, NumObjects * sizeof(T));

            delete [] NewMem;
        }

        MT[MemBlockNum].MemBlock = MemBlock;
        MT[MemBlockNum].Allocated = true;
        MT[MemBlockNum].NumObjects = Num;
    }
    else
    {
        MemBlock = Allocate<T>(Num);
    }
    
    return MemBlock;
}

template <typename T>
void MEMORY::Deallocate(T *MemBlock)
{
    unsigned long i;

    for(i = 0; i < NumMemBlocks; i++)
    {
        if(MT[i].MemBlock == MemBlock && MT[i].Allocated)
        {
            free(MemBlock);
            MT[i].Allocated = false;
        }
    }
}

class DLLIMPORT MemOrg
{
public:
    static MEMORY &GetMemory();
private:
    static MEMORY Mem;
};

//////////////////////////

// memorg.cpp

#include "memorg.h"

MEMORY MemOrg::Mem;

MEMORY::MEMORY()
{
    MT = (MEMORYTRACKER *) malloc(0);
    NumMemBlocks = 0;
}

MEMORY::~MEMORY()
{
    unsigned long i;
    
    for(i = 0; i < NumMemBlocks; i++)
    {
        if(MT[i].Allocated)
        {
            free(MT[i].MemBlock);
        }
    }
    
    free(MT);
}

MEMORY &MemOrg::GetMemory()
{
    return Mem;
}
I've tried re-writing the code so that all dynamic memory allocation is done purely with new and delete, yet the same problem occurs so I know it's nothing to do with that (I have my own reasons for using C-style memory allocation in places so I'm not looking to start a malloc vs new debate or anything like that). I'm sure there's something small that I'm missing here, but I'm at my wits end trying to resolve this situation. If anyone can shed any insight it would be much appreciated.

Kind regards,

BLauritson