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; }



LinkBack URL
About LinkBacks


