Как использовать распределители в современном С++

Из того, что я читал в http://en.cppreference.com/w/cpp/memory/allocator, большинство функций распределителей теперь будут устаревать. Вопрос в том, как следует использовать распределители в новом коде? Каков сейчас "правильный" способ?

Из того, что я выводил в документации, construct является частью признаков распределителя, а не самого распределителя.

Я создаю пользовательский контейнер, здесь это очень простая версия конструктора, это хорошее использование нового дизайна?

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)
    }
}

Я попытался использовать в цикле алгоритм (например, std::for_each), но мне не удалось использовать его без адреса (operator&).

Где я могу найти полный пример современного распределителя?


После некоторой настройки я нашел способ использовать алгоритм вместо необработанного цикла (которому может быть передана политика выполнения). Я не очень уверен, но это может быть так:

    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);}
    );

Ответ 1

Да, текущий подход проходит через std::allocator_traits. Таким образом, вы сможете поддерживать "минимальный интерфейс распределителя".

http://en.cppreference.com/w/cpp/concept/Allocator

Некоторые требования являются необязательными: шаблон std::allocator_traits предоставляет стандартные реализации для всех необязательных требований, а все стандартные библиотеки и другие классы, имеющие доступ к распределителю, получают доступ к распределителю через std::allocator_traits, а не напрямую.

Если вы наблюдаете функции-члены std::allocator_traits и typedefs, вы увидите, что они обнаруживают наличие соответствующих функций/типов и отправляют через них, если могут.

Устранение и потенциальное удаление в будущем ничего не изменят, если вы уже используете std::allocator_traits, поскольку он применим только к std::allocator и к его функциям-членам/typedefs.

Теперь, если вы спросите меня, нет ничего плохого в for-loops, и использование std::for_each не принесет вам ничего. Существует несколько функций uninitialized_*, но они напрямую используют размещение new. Если вам действительно интересно, вы можете извлечь этот код в отдельную функцию construct_range.

Также существует проблема с безопасностью исключения - в случае, если один из конструкторов бросает, вам нужно уничтожить более ранние элементы, чтобы удовлетворить сильную гарантию исключения и освободить память (деструктор не будет вызван в случае, если конструктор выбрасывает)