4
\$\begingroup\$

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_ptrs 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
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.