Custom STL allocators

If we are using an STL container, we cannot simply replace its allocator in the manner that has been discussed previously, because their elements often have an implementation-defined type we cannot access. For that reason, we had the std::Allocator class, which could be passed to the collection and used to allocate its single elements. However, owing to the language limitations of C++ at that time, these allocators were extremely clunky to use and generally were little loved (not to say hated) in the C++ community. This is a pity, as allocators were designed as a way to customize the behavior of STL containers.

However, C++11 simplified the allocator API to such an extent that they can now indeed be used without that much pain. To prove that, here is a standard example of a simple, stateless C++11 allocator:

template <class T>
struct TestAlloc
{
typedef T value_type;
TestAlloc() = default;
template <class U> constexpr TestAlloc(const TestAlloc<U>&) noexcept {}

T* allocate(std::size_t n)
{
if(auto p = static_cast<T*>(std::malloc(n*sizeof(T)))) return p;
throw std::bad_alloc();
}
void deallocate(T* p, std::size_t) noexcept { std::free(p); }
};

template <class T, class U> bool operator==(const TestAlloc<T>&, const TestAlloc<U>&)
{ return true; }
template <class T, class U> bool operator!=(const TestAlloc<T>&, const TestAlloc<U>&)
{ return false;}

We see there is still some amount of plumbing needed, but not too much. If you'd like to learn more about implementing allocators, please refer to the C++ books in the Further reading section.