1

I'm trying to design the internal mechanics of a simple embedded application. Chunks of data arrive on the network which need to be delivered to components determined by an addressing mechanism. Multiple components may subscribe to the same address. I want to design an architecture where incoming chunks are encapsulated into wrapper objects allocated from a memory pool. Each component might hold onto the wrappers (and the data inside them) as long as they need and it should be freed when all components let go of it. At that time it's returned to the pool and again ready to be allocated. The pool exhausting is not a concern.

I plan to use this memory pool implementation which satisfies Allocator. For the automatic destruction of wrapper objects I plan to use std::shared_ptr so when all components free the wrapper, it is automatically destroyed and the used memory returned to the pool.

What I don't see is how these two concepts can come together. If I allocate memory from the pool directly (by calling allocate()), it would give me a pointer to the block of data which is fine but then how will deallocate() be called automatically? Or do I need to use another container for my wrapper objects like std::list and pass it the memory pool allocator?

1 Answers1

0

You can use std::shared_ptr with a custom allocator using std::allocate_shared. This is probably what you want anyway, since I'm assuming you want the control block (i.e. reference counts) to be allocated using the pool allocator as well.

When constructing an object using std::allocate_shared, a copy of the allocator is stored inside the shared_ptr, so the correct deallocate() will be called on destruction.

Note that you could also create your std::shared_ptr using a custom deleter, e.g.:

auto allocator = getAllocator<Foo>();
auto ptr = std::shared_ptr<Foo>(new(allocator.allocate()) Foo,
  [&allocator](auto * ptr) { allocator.deallocate(ptr); });

However, as I mentioned that's probably not what you want, since space for the reference counts will not be allocated using your allocator object.

Btw, in case you're still "shopping around", here is another memory pool implementation which I quite like: foonathan::memory. It provides its own allocate_shared.

AVH
  • 11,349
  • 4
  • 34
  • 43
  • Thanks for the answer. There's one thing about this: the slots in a memory pool have a fixed size that must be known at compile time. How do I calculate that? I know the size of the objects I want to allocate, same for the allocator (needed because of the copy), but what about the control block? – Szabolcs Szekelyi Mar 03 '20 at 05:05
  • Good questions and one thing I like about the foonathan::memory library, since it has a bunch of helper functionality to help with exactly such things. I took a cursory look at `shared_prt`'s API, but can't see anything to let you figure out the size of the control block... – AVH Mar 03 '20 at 08:56