std::uninitialized_move с определенным распределителем

Я пишу собственный класс шаблона контейнера, который, как и многие (если не все) контейнеры в stl, может использовать указанный тип распределителя. Чтобы реализовать функцию вставки диапазона, мне нужно переместить некоторые элементы в контейнере на несколько пробелов вперед, где память все еще не инициализирована. Для этого я хочу использовать некоторую (несуществующую) версию std::uninitialized_move(), которая использует распределитель в контейнере.

Другой вариант — выполнить перемещение объектов с помощью распределителя в цикле for и уничтожить созданные объекты в случае исключения. Это в основном повторная реализация std::uninitialized_move() с дополнительной функцией.

Реализация стандартной библиотеки для моего компилятора (GCC) имеет именно те функции, которые мне нужны (std::__uninitialized_move_a(), std::__uninitialized_copy_a() и т. д.), и фактически используются в реализации стандартных контейнеров, но я думаю, что они скорее специфичны для компилятора.

Должен ли я использовать эти функции (переносимость)? Или есть другой, более практичный вариант? Может быть, в стандартной библиотеке есть что-то, чего мне не хватает.


person DeltA    schedule 07.09.2020    source источник


Ответы (1)


Должен ли я использовать эти функции (переносимость)?

Вы не должны использовать внутренние функции GCC.

Нет, похоже, не существует стандартных эквивалентов. Вы можете написать свои собственные версии этих функций. Если вы это сделаете, обратите внимание, что CustomAlloc::construct — необязательная функция (например, std::allocator не имеет этой функции, начиная с C++20), поэтому ее следует использовать до std::allocator_traits<CustomAlloc>::construct. Это имеет дополнительное преимущество в том, что он является constexpr, начиная с C++20.

Или есть другой, более практичный вариант?

Один из вариантов — игнорировать возможность того, что CustomAlloc::construct был реализован для чего-то другого, кроме прямого размещения new, и, таким образом, просто использовать стандартный std::uninitialized_move.

Это технически ограничивает аллокаторы, которые теоретически поддерживает ваш контейнер, но, с другой стороны, я никогда не видел, чтобы такой пользовательский аллокатор использовался на практике. Это может быть разумным ограничением, если контейнер предназначен как минимум для внутреннего использования. Если вы сделаете это, тщательно задокументируйте поведение.

person eerorika    schedule 07.09.2020
comment
Спасибо за разъяснения о внутренностях GCC. Оба варианта кажутся хорошими. - person DeltA; 07.09.2020