I put together this little memory pool class to help avoid the costs associated with heap allocation and deallocation of objects that are frequently created & destroyed. It creates C++ standard shared_ptr
s with custom deleters that return the pointed-to object to the memory pool where it can be recycled. Right now it uses the moodycamel queue to manage the pool, but it could be rewritten to use a simple vector or stack instead.
I'd appreciate any comments on design / implementation.
#ifndef SHAREDPTRMEMORYPOOL_H
#define SHAREDPTRMEMORYPOOL_H
#include <memory>
#include <3rdParty/spsc_queue/readerwriterqueue.h>
// Objects to be managed must have a default constructor
// and a reconstruct(...) function which serves to initialize
// their state (like a constructor)
//
// Use like:
// auto obj = make_shared_ptr_from_pool(my_memory_pool, my_reconstruct_args, ...);
template<class TPointedToClass>
class SharedPtrMemoryPool {
public:
explicit SharedPtrMemoryPool(unsigned int num_to_prealloc);
~SharedPtrMemoryPool();
std::shared_ptr<TPointedToClass> get_shared_ptr();
void release_shared_ptr(TPointedToClass* to_release);
private:
moodycamel::ReaderWriterQueue<TPointedToClass*> _pointer_queue;
};
template<class TPointedToClass>
SharedPtrMemoryPool<TPointedToClass>::SharedPtrMemoryPool(unsigned int num_to_prealloc) {
for(unsigned int i = 0; i < num_to_prealloc; ++i) {
auto prealloc_item = new TPointedToClass();
_pointer_queue.enqueue(prealloc_item);
}
}
template<class TPointedToClass>
SharedPtrMemoryPool<TPointedToClass>::~SharedPtrMemoryPool() {
TPointedToClass* raw_ptr;
while(_pointer_queue.try_dequeue(raw_ptr)) {
delete raw_ptr;
}
}
template<class TPointedToClass>
std::shared_ptr<TPointedToClass> SharedPtrMemoryPool<TPointedToClass>::get_shared_ptr() {
TPointedToClass* raw_retval;
bool recycle_success = _pointer_queue.try_dequeue(raw_retval);
if(!recycle_success) {
raw_retval = new TPointedToClass();
}
return std::shared_ptr<TPointedToClass>(raw_retval, [this](TPointedToClass* to_release) {
this->release_shared_ptr(to_release);
});
}
template<class TPointedToClass>
void SharedPtrMemoryPool<TPointedToClass>::release_shared_ptr(TPointedToClass* to_release) {
_pointer_queue.enqueue(to_release);
}
template<class TPointedToClass, class... Args>
std::shared_ptr<TPointedToClass> make_shared_ptr_from_pool(SharedPtrMemoryPool<TPointedToClass>& pool, Args&&... args) {
std::shared_ptr<TPointedToClass> retval = pool.get_shared_ptr();
retval->reconstruct(std::forward<Args>(args)...);
return retval;
}
#endif