From what I read in http://en.cppreference.com/w/cpp/memory/allocator , most features of the allocators are now going to be deprecated. The question is, how is one supposed to use allocators in new code? What is the "right" way now?
From what I deduce in the documentation, construct
is part of the allocator traits, rather than the allocator itself.
I am building a custom container, here it is a very simple version of the constructor, is this a good usage of the new design?
container::container(std::size_t size, T const& value, Allocator const& allocator) : allocator_(allocator){
data_ = std::allocator_traits<Alloc>::allocate(allocator_, size);
for(auto ptr = data_; ptr != data_ + size; ++ptr){
std::allocator_traits<Allocator>::construct(allocator_, ptr, value)
}
}
I tried to use an algorithm (like std::for_each
) in the loop but I didn't manage to use one without taking addresses (operator&
).
Where can I find a complete example of a modern allocator?
After some tweaking, I found a way to use an algorithm instead of the the raw loop (to which an execution policy can be passed). I am not very sure, but it could be this:
data_ = std::allocator_traits<Allocator>::allocate(allocator_, size);
std::for_each([policy? deduced from allocator?,]
boost::make_counting_iterator(data_),
boost::make_counting_iterator(data_ + size),
[&](auto ptr){std::allocator_traits<Allocator>::construct(allocator_, ptr, value);}
);
Yes, the current approach is through
std::allocator_traits
. You'll be able to support the "minimal allocator interface" that way.http://en.cppreference.com/w/cpp/concept/Allocator
If you observe the
std::allocator_traits
member functions and typedefs, you'll see they're detecting the presence of appropriate function/types and dispatching through them if they can.The deprecation and potential future removal will change nothing if you're already using
std::allocator_traits
since it only applies tostd::allocator
and their member functions/typedefs.Now, if you ask me, there's nothing wrong with for-loops, and using
std::for_each
gains you nothing. There are severaluninitialized_*
functions, but they use placement new directly. If you really care you can extract this code to a separateconstruct_range
function.There's also an exception safety issue - in case one of the constructors throws, you need to destroy the earlier elements in order to satisfy the strong exception guarantee and free the memory too (destructor won't get called in case constructor throws)