According to http://en.cppreference.com/w/cpp/concept/Allocator, one class that can be used as an allocator type must meet many requirements. However, I cannot find the same requirements specified by the C++ standard. The standard only requires the allocator type must not be a non-class type. (see n3797 20.7.8.1)
If I have an empty class Alloc
and a fully specialized std::allocator_traits<Alloc>
, can I use Alloc
as follows:
#include <vector>
struct Alloc {};
template<>
std::allocator_traits<Alloc>
{
// full of definitions as per the requirements for std::allocator_traits<T>
};
int main()
{
std::vector<int, Alloc> coll;
coll.push_back(8);
}
As long as you are going to use the allocator with STL containers (or code that adheres to the same conventions) you can define your allocator by just specialising std::allocator_traits
for your class (for which it then just suffices to be defined; thinking of it, I think you might even hijack an existing non-allocator class for this purpose), since calls to your allocator will not be made directly, but through the std::allocator_traits
specialisation.
Doing so seems to defeat the purpose of that class template however, since by defining that specilisation your are loosing all the defaults that the template has put in place, so you have to redefine everything, which is not easier than defining everything in your Alloc
class directly. Specifically, 17.6.4.2.1 appears to make it undefined behavior to just specialise individual member functions like std::allocator_traits<Alloc>::allocate
, which must of course be defined.
The intended use is clearly to not specilialise std::allocator_traits
at all, but just define those members of Alloc
for which no defaults are provided (essentially value_type
, allocate
and deallocate
; at the end of 17.6.3.5 there is an example struct SimpleAllocator
that provides a minimal working interface), or for which you want to override the defaults (std::allocator_traits
is set up to use any defined members with preference over its defaults).
As a personal matter, I would advise to normally always override the typedefs propagate_on_container_move_assignment
and propagate_on_container_swap
(but not their copy_assignment
relative) from their default false_type
state to true_type
. Since container class templates cannot allow a non-equivalent allocator instance to be associated with existing memory (which would ultimately cause it to be deallocated incorrectly), they must be prepared to abandon move semantics and reallocate everything in case (the relevant one of) the two mentioned types are false_type
and allocator instances are found to be unequal. It might be that the compiler is smart enough to detect that for your (stateless) allocator type instances can never compare unequal, and treat the above "be prepared" complication as dead code. However this dead code treatment this is easier to detect and more certain to happen if that type is true_type
, and will then also apply for statefull allocators (allowing propagation). Stated differently, I think those two defaults are just chosen wrong.