I'm writing a container and would like to permit the user to use custom allocators, but I can't tell if I should pass allocators around by reference or by value.
Is it guaranteed (or at least, a reasonable assumption to make) that an allocator object will not contain its memory pool directly, and hence it would be OK to copy an allocator and expect the memory pools of the allocators to be cross-compatible? Or do I always need to pass allocators by reference?
(I have found that passing by reference harms performance by a factor of > 2 because the compiler starts worrying about aliasing, so it makes a whether or not I can rely on this assumption.)
The old C++ standard makes requirements for a standard-compliant allocator: These requirements include that if you have
Alloc<T> a, b
, thena == b
, and you can useb
to deallocate things that were allocated witha
. Allocators are fundamentally stateless.In C++11, the situation got a lot more involved, as there is now support for stateful allocators. As you copy and move objects around, there are specific rules whether one container can be copied or moved from another container if the allocators differ, and how the allocators get copied or moved.
Just to answer your question first: No, you can definitely not assume that it makes sense to copy your allocator around, and your allocator may not even be copyable.
Here is 23.2.1/7 on this subject:
See also the documentation of
std::allocator_traits
for a synopsis.In C++11 section 17.6.3.5 Allocator requirements [allocator.requirements] specifies the requirements for conforming allocators. Among the requirements are:
I.e. when you copy an allocator, the two copies are required to be able to delete each other's pointers.
Conceivably one could put internal buffers into allocators, but copies would have to keep a list of other's buffers. Or perhaps an allocator could have an invariant that deallocation is always a no-op because the pointer always comes from an internal buffer (either from your own, or from some other copy).
But whatever the scheme, copies must be "cross-compatible".
Update
Here is a C++11 conforming allocator that does the "short string optimization". To make it C++11 conforming, I had to put the "internal" buffer external to the allocator so that copies are equal:
It could be used like this:
All allocations for the above problem are drawn from the local
arena
which is 1 Kb in size. You should be able to pass this allocator around by value or by reference.