An allocator can be given as a template template parameter
The resulting template should look something like this:
template<template <typename T> typename ALLOCATOR = std::allocator>
class Foo
{
class Bar
{
// stuff
};
using Allocator = ALLOCATOR<Bar>;
using Container = std::vector<Bar, Allocator >;
Foo(const Allocator& allocator = Allocator{}):
contents(allocator)
{
}
private:
Container<Allocator> contents;
};
You can now use it with std::allocator as:
Foo<> asBefore;
or with your own allocator as:
MyAllocator alloc(params);
Foo<MyAllocator> foo(alloc);
You might be able to wrap your Container class using a trick like the one given here so that you don't have to convert the whole class to a template. This would let you keep your encapsulation.
I have not attempted this here.
Beware that:
Foo<MyAllocator> foo(MyAllocator(params)); //BAD
Is a somewhat vexing parse which generally won't work.
Also note that older compilers such as gcc 4.8 on RHEL7 do not allow typename
for template template parameters
so you must use class
instead. See How can I use templete template parameters in older C++ compilers?
That is:
template<template <class T> class ALLOCATOR = std::allocator>
class Foo
...
For completeness, if you do have C++17
or later, another alternative is polymorphic allocators. These potentially add the overhead of a virtual function call to every allocation but this is often less significant than the cost of a malloc
. In the right circumstances the compiler may be able to eliminate this completely.
See for example polymorphic_allocator: when and why should I use it?
In this case your class wouldn't have to be converted into a template which may help with encapsulation.
class Foo
{
class Bar
{
// stuff
};
using Container = std::pmr::vector<Bar>;
Foo(const std::polymorphic_allocator& allocator = std::pmr::get_default_resource()):
contents(allocator)
{
}
private:
Container<Allocator> contents;
};
Note that std::pmr::vector<Bar>
is basically shorthand for std::vector<Bar, std::pmr::polymorphic_allocator<Bar> >
;