Ok, so I was bored today and decided to write a simple memory pooling demo, where I have a singleton memory_pool object, and then the clients of the memory pool make use of it by overloading new and delete. The memory_pool exists on a per type basis, which is done with templates.

So first I have a general question about singletons, and second I was looking for general feedback, in terms of if my memory_pool object is implemented incorrectly, could be doing something better, etc. Also I've never actually overloaded new/delete before, so I was wondering if there were special issues I should be aware of.

Question 1: How do I get the singleton destructor to fire? As far as I can tell, it never will fire, because I would need to explicitly call delete against my instance_ pointer. Is there a standard way to do this?

Question 2: Is there any improvements I can make, or did I implement anything incorrectly? There are two shortcomings that I can see right away: a) Not thread-safe (easy to fix); b) new[] and delete[] are not handled by the memory_pool, so global new[] and delete[] would be used (not so easy to fix, the implementation would probably have to be completely different).

Ok, here's the code:

Code:
# include <new>
# include <list>
# include <algorithm>
# include <iostream>
using namespace std;

template <class T, int N = 100>
class memory_pool {
    class delete_it {
        public:
        void operator()(char* p) {
            cout << "Deleting memory at " << p << endl;
            delete[] p;
        }
    };

    memory_pool() {
        // preallocate N objects
        alloc_n();
    }

    void alloc_n() {
        for (int i = 0; i < N; i++) {
            char* p = new char[sizeof(T)];

            cout << "Allocating memory at " << reinterpret_cast<T *>(p) << endl;

            pool_.push_back(p);
        }
    }

    public:

    virtual ~memory_pool() {
        // destroy each object still inuse
        while (!inuse_.empty()) {
            char* p = inuse_.front();
            Destroy(p);
        }

        // delete all pooled objects
        for_each(pool_.begin(), pool_.end(), delete_it());
    }

    static memory_pool<T,N>* Instance() {
       if (!memory_pool<T,N>::instance_) memory_pool<T,N>::instance_ = new memory_pool<T,N>();

       return memory_pool<T,N>::instance_;
    }

    T* Create() {
        if (pool_.empty()) {
            // allocate N more objects
            alloc_n();
        }

        // remove element from available pool
        char* p = pool_.front();
        pool_.pop_front();

        // put onto inuse list
        inuse_.push_back(p);

        return reinterpret_cast<T*>(p);
    }

    private:
    void Destroy(char* p) {
        // remove element from inuse pool
        inuse_.remove(p);

        // add back to available pool
        pool_.push_back(p);
    }
    public:
    void Destroy(T* p) {
        Destroy(reinterpret_cast<char *>(p));
    }

    static memory_pool<T,N>* instance_;

    private:
    list<char*> pool_;
    list<char*> inuse_;
};

class Demo {
    int x;

    public:
    Demo() {
        x = 0;
        cout << "Constructing Demo " << this << endl;
    }

    ~Demo() {
        cout << "Destructing Demo " << this << endl;
    }

    void* operator new(size_t sz);

    void operator delete(void* p, size_t sz);
};

typedef memory_pool<Demo,5> DemoPool;
DemoPool* DemoPool::instance_ = 0;

void* Demo::operator new(size_t sz) {
   return DemoPool::Instance()->Create();
}

void Demo::operator delete(void* p, size_t sz) {
    DemoPool::Instance()->Destroy(static_cast<Demo *>(p));
}

int main() {

    for (int i = 0; i < 10; i++) {
        Demo* d = new Demo();
        delete d;
    }

    return 0;
}