8
\$\begingroup\$

I'm using a third-party library which utilizes boost::shared_ptr for memory management.

The problem is that I need to allocate many objects and I have detected that the allocation and deallocation is rather resource-demanding. So I thought I should utilize a smart-pointer memory pool to reduce the overhead.

#include <boost/smart_ptr/make_shared_array.hpp>

template <class T, size_t pool_size>
class shared_ptr_pool
{
   boost::shared_ptr<T[]> pool;
   size_t avail = 0;

public:
   boost::shared_ptr<T> make_shared()
   {
      if (!avail)
      {
         pool = boost::make_shared<T[]>(pool_size);
         avail = pool_size;
      }

      return boost::shared_ptr<T>(pool, &pool[--avail]);
   }
};

The solution is to utilize make_shared for arrays and the shared_ptr aliasing constructor. The solution in inherently thread-unsafe, but for my needs that is okay.

Any thoughts, comments or pretty much anything would be appreciated.

\$\endgroup\$
  • \$\begingroup\$ The main advantage of a pool is that released pointers can quickly be re-used. I don't see that functionality here. Once your pool is empty you need to re-create another pool. \$\endgroup\$ – Martin York Mar 24 '14 at 1:07
  • \$\begingroup\$ This might be a silly question. But why would you use a third party library for something that is already in the language? \$\endgroup\$ – Mads Mar 25 '14 at 1:26
  • 1
    \$\begingroup\$ @Mads: The third-party library I use in turn use boost::shared_ptr because of performance, portability and it correctly uses delete[] on array types. \$\endgroup\$ – dalle Mar 25 '14 at 8:44
  • \$\begingroup\$ @LokiAstari: You are correct, this isn't a pool as such, as it doesn't return objects to the pool, but a chunk-allocator-thingy (?). \$\endgroup\$ – dalle Mar 25 '14 at 8:46
5
\$\begingroup\$

Per the comments, this isn't really a "pool" because things don't go back into it when you're done using them. It's just an "incremental allocator" that does allocation in "chunks". A better name for it might be shared_ptr_chunk_allocator (and chunk_size instead of pool_size).

Given that pool_size is used only on the codepath that also allocates memory (so it's not a super speed-critical path where one more memory load would hurt performance), and shared_ptr_pool<...> has non-static data members (so there's no harm in adding one more non-static data member), surely it would make more sense to make pool_size a runtime parameter to shared_ptr_pool's constructor.

// your current code:
shared_ptr_pool<myclass, 16> pool;
// versus my suggestion:
shared_ptr_pool<myclass> pool(16);

This would even allow you to provide a member function for modifying the chunk size on the fly, in case maybe your code could detect that its particular workload demanded a bigger chunk size.

if (memory_usage_low && still_spending_lots_of_time_in_allocation) {
    pool.set_chunk_size(pool.chunk_size() * 2);
}

The actual code implementation looks fine to me; nothing to complain about there. :)

You might be pleased to (or, you might already) know that std::shared_ptr<T[]> is part of the Library Fundamentals v1 Technical Specification, which I think means it ought to be coming to C++1z. However, it's not in the working draft yet as of N4567 (November 2015).

\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.