Search code examples
c++c++11allocatorplacement-newc++20

uninitialized_X functions that use the allocator constructor?


Is there a version of uninitialized_value_construct that uses the an allocator to construct the element in place instead of placement new?

This below is the prototypical implementation of uninitialized_value_construct; however I am looking for one where the allocator is passed so I can use the line alloc.construct(std::addressof(*current)) instead of ::new (std::addressof(*current)).

template<class ForwardIt>
void uninitialized_value_construct(ForwardIt first, ForwardIt last)
{
    using Value = typename std::iterator_traits<ForwardIt>::value_type;
    ForwardIt current = first;
    try {
        for (; current != last; ++current) {
            ::new (static_cast<void*>(std::addressof(*current))) Value();
        }
    } catch (...) {
        std::destroy(first, current);
        throw;
    }
}

In C++20, there is uninitialized_construct_using_allocator but it is not clear what it is for or how to use it.


EDIT: After a conversation with @NicolBolas, I ended up implementing these pair of functions (that I wish were in the std::). For my needs (and without loss of generality, I will do this for other uninitialized_X functions.

template<class Alloc, class ForwardIt, class Size, class AT = typename std::allocator_traits<Alloc>>
ForwardIt uninitialized_value_construct_n(Alloc& a, ForwardIt first, Size n){
    using T = typename std::iterator_traits<ForwardIt>::value_type;
    ForwardIt current = first;
    try{
        for(; n > 0; (void) ++current, --n) 
            AT::construct(a, std::addressof(*current), T());
//          ::new (static_cast<void*>(std::addressof(*current))) T();
        return current;
    }catch(...){destroy(a, first, current); throw;}
}
template<class Alloc, class ForwardIt, typename AT = typename std::allocator_traits<Alloc> >
void destroy(Alloc& a, ForwardIt first, ForwardIt last){
    for(; first != last; ++first) 
        AT::destroy(a, std::addressof(*first));
    //  destroy_at(std::addressof(*first));
}

Solution

  • Sadly, there is no ranged version of uninitialized_construct that takes an allocator.

    As for what uninitialized_construct_using_allocator is for, it construct a single object of the given type with the given arguments through the allocator. That might seem trivial to do (std::allocator_traits<Alloc>::construct(t, alloc, std::forward<Args>(args)...)), but it does it in such a way that the allocator will be propagated correctly to scoped_allocators used by that T. This requires a bunch of techniques that are not well known and are not easily understood, so there's a specific function to do it.