1

When we supply an allocator for std::vector in C++, note that we supply an allocator class. A class cannot be created at runtime.

However, what if I need my allocator to depends on runtime information? For example, we might need to determine how to allocate from the particular user input. Or, if we want to create a vector by using virtual memory from mmaping a file, but the file is not known at compile time, then we also need this. Surely we can use global variables for this, but surely that's not a good way.

Is it possible to store such runtime information in the use of std::vector?

The question is simple enough. However, after looking around, I see no answers at all. Apparently there are no elegant ways to do this?

  • 1
    `std::vector` has constructors that take an allocator object and it will use that object for allocations – NathanOliver Jun 14 '23 at 16:58
  • 1
    Did STL have allocators? I wasn't really into C++ back when people used the STL. – user4581301 Jun 14 '23 at 17:25
  • 1
    @user4581301 -- STL had allocators, but their purpose was primarily to provide appropriate type names for pointers and references to support Windows memory models, for example, so that you could use FAR pointers in containers in a program that was compiled for a memory model that used NEAR pointers. – Pete Becker Jun 14 '23 at 17:54
  • @PeteBecker Thanks. It's good to know history so you don't have to repeat it. Or at least not the bad parts. – user4581301 Jun 14 '23 at 18:04
  • 1
    @user4581301 -- on reflection, it wasn't **just** about type names; allocators also had functions to allocate and free memory (just like today), which, of course, you needed if you were allocating, for example, FAR data in a NEAR memory model. But the motivation was Windows. – Pete Becker Jun 14 '23 at 18:13

2 Answers2

1

It sounds like you're looking for std::pmr::polymorphic_allocator, which is an allocator that is constructed from a std::pmr::memory_resource (which is effectively an allocator). This lets you effectively choose the allocator at runtime.

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
1

Yes, it's possible. All containers in the standard library satisfy the allocator-aware requirement. In simple terms, this means that the container has to store an allocator as a subobject, and handle this object correctly when the container is copied, moved, etc. There are two approaches to implementing stateful allocators:

Stateful Static Allocators

template <typename T>
struct mmap_allocator { /* ... */ };

mmap_allocator<data> create_mmap_allocator(std::string_view file) { /* ... */ }

auto create_vec() {
    std::vector<data, mmap_allocator<data>> result(create_mmap_allocator());
    /* ... */
    return result;
}

mmap_allocator can store state, such as which file was opened, a pointer to the mapped memory, etc. An obvious downside is that this std::vector is now distinct from a regular std::vector, since it uses a custom allocator.

Polymorphic Allocators

If you want even more customization, such as using a totally different type of allocator in the same vector type, this becomes annoying. It's also annoying that std::vector<T> and std::vector<T, mmap_allocator<T>> are incompatible. To solve this, there are polymorphic allocators:

struct mmap_resource : std::pmr::memory_resource { /* ... */ };

mmap_resource create_mmap_resource(std::string_view file) {
    /* ... */
}

auto use_vec() {
    // TODO: the allocator doesn't own the memory resource, so
    //       we might need to bundle the vector and the resource in
    //       a struct, etc.
    auto resource = create_mmap_resource(...);
    std::pmr::polymorphic_allocator alloc = &resource;
 
    std::pmr::vector<data> result(alloc);
    /* ... */
}

Polymorphic allocators are wrappers for a polymorphic class std::pmr::memory_resource, which you can customize.

Also see: polymorphic_allocator: when and why should I use it?

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96