Search code examples
c++listmemory-managementc++11placement-new

Placement new with std::list


I am looking to implement a (doubly) linked list which only calls placement new internally, directing all memory to a pool allocated with something like:

char *memPool = new char[4096]; // One-off normal 'new'

Initially I was going to implement my own class which takes a pointer to a (class managing a) pre-allocated memory pool. However I want to be sure first that I can't achieve the same outcome with std::list. In particular, the third section of David Rodríguez's answer to this SO question worries me.

It makes sense that std::list will have to call new and delete on its component nodes, but I want to modify this behaviour so that all the nodes to be allocated with placement new into my custom pool. Therefore my question is:

Is there a way to specify that a placement new std::list such as:

std::list<std::shared_ptr<Cls>> myList = new (pool.getFreeAddr()) list<Cls>;

should also allocate its nodes using a custom allocator, so that everything is stored strictly inside my own memory pool?

(Note: I am aware of the need to use custom allocation/deletion functions with the shared_ptrs if I want them in the custom memory pool too.)


Solution

  • You have to:

    • Write a class template MyAllocator that satisfies the Allocator requirements ([allocator.requirements] in the standard).
    • Use a std::list<T, MyAllocator<T> > in place of a std::list<T>.

    If you need the type of your list to be specifically std::list<T> (for example because you want to call functions that accept a std::list<T> & and whose interface you can't change), then you're out of luck because the allocator type is part of the container type.

    Be careful about the allocator requirements, they're strange. In particular you will need rebind for a list, and it's a bit tricksy.

    Furthermore, in C++03 there's no guarantee that allocator instances are respected, only the allocator type, which in effect means that the pointer to the pool you're allocating from needs to be stored with static duration rather than as an instance variable. I think that was changed in C++11, but I might be wrong. It only really matters if you want to use multiple different pools in your program.