简体   繁体   中英

Can I use any class T as an allocator type as long as std::allocator_traits<T> is specialized?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM