Spec-Zone.ru › C++

std::uninitialized_move

Определён в заголовочном файле <memory>
template< class InputIt, class NoThrowForwardIt >
NoThrowForwardIt uninitialized_move( InputIt first, InputIt last,
                                     NoThrowForwardIt d_first );
(1) (начиная с C++17)
(constexpr начиная с C++26)
template< class ExecutionPolicy,
          class ForwardIt, class NoThrowForwardIt >
NoThrowForwardIt uninitialized_move( ExecutionPolicy&& policy,
                                     ForwardIt first, ForwardIt last,
                                     NoThrowForwardIt d_first );
(2) (начиная с C++17)
1) Создаёт элементы в целевом диапазоне, начиная с d_first, из элементов исходного диапазона [first, last), как если бы выполнялось

for(;first!=last;++d_first,(void)++first)
    ::new(voidify(*d_first))
        typenamestd::iterator_traits<NoThrowForwardIt>::value_type(deref-move(*iter));
returnd_first;

Если во время инициализации возникает исключение, некоторые объекты в [first, last) остаются в допустимом, но неуказанном состоянии, а уже созданные объекты уничтожаются в неуказанном порядке.
2) То же, что и (1), но выполняется согласно policy.
Эта перегрузка участвует в разрешении перегрузки, только если значение следующего выражения равно true:

std::is_execution_policy_v<std::decay_t<ExecutionPolicy>>

(до C++20)

std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>>

(начиная с C++20)

Если d_first + [0, std::distance(first, last)) пересекается с [first, last), поведение не определено.

(начиная с C++20)

Параметры

first, last - пара итераторов, задающих диапазон перемещаемых элементов
d_first - начало целевого диапазона
policy - используемая политика выполнения
Требования к типам
-InputIt должен удовлетворять требованиям LegacyInputIterator.
-ForwardIt должен удовлетворять требованиям LegacyForwardIterator.
-NoThrowForwardIt должен удовлетворять требованиям LegacyForwardIterator.
-Инкремент, присваивание, сравнение и разыменование допустимых экземпляров NoThrowForwardIt не должны вызывать исключения.

Возвращаемое значение

Как описано выше.

Исключения

2) Во время выполнения:
  • Если временные ресурсы памяти, необходимые для параллелизации, недоступны, выбрасывается std::bad_alloc.
  • Если при доступе к объектам через аргумент алгоритма возникает неперехваченное исключение, поведение определяется политикой выполнения (для стандартных политик вызывается std::terminate).

Примечания

Если входной итератор разыменовывается в rvalue, поведение std::uninitialized_move совпадает с поведением std::uninitialized_copy.

Макрос проверки поддержки возможностей Значение Стандарт Возможность
__cpp_lib_raw_memory_algorithms 202411L (C++26) constexpr для специализированных алгоритмов <memory>, (1)

Возможная реализация

template<class InputIt, class NoThrowForwardIt>
constexpr NoThrowForwardIt uninitialized_move(InputIt first, InputIt last,
                                              NoThrowForwardIt d_first)
{
    using ValueType = typename std::iterator_traits<NoThrowForwardIt>::value_type;
    auto current = d_first;
    try
    {
        for (; first != last; ++first, (void) ++current)
        {
            auto addr = static_cast<void*>(std::addressof(*current));
            if constexpr (std::is_lvalue_reference_v<decltype(*first)>)
                ::new (addr) ValueType(std::move(*first));
            else
                ::new (addr) ValueType(*first);
        }
        return current;
    }
    catch (...)
    {
        std::destroy(d_first, current);
        throw;
    }
}

Пример

#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <memory>
#include <string>

void print(auto rem, auto first, auto last)
{
    for (std::cout << rem; first != last; ++first)
        std::cout << std::quoted(*first) << ' ';
    std::cout << '\n';
}

int main()
{
    std::string in[]{"Home", "Work!"};
    print("initially, in: ", std::begin(in), std::end(in));
    
    if (constexpr auto sz = std::size(in);
        void* out = std::aligned_alloc(alignof(std::string), sizeof(std::string) * sz))
    {
        try
        {
            auto first{static_cast<std::string*>(out)};
            auto last{first + sz};
            std::uninitialized_move(std::begin(in), std::end(in), first);
            
            print("after move, in: ", std::begin(in), std::end(in));
            print("after move, out: ", first, last);
            
            std::destroy(first, last);
        }
        catch (...)
        {
            std::cout << "Exception!\n";
        }
        std::free(out);
    }
}

Возможный вывод:

initially, in: "Home" "Work!"
after move, in: "" ""
after move, out: "Home" "Work!"

Отчёты об ошибках

Следующие отчёты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Применён к Опубликованное поведение Корректное поведение
LWG 3918 C++17 Перемещающее конструирование всегда выполняется, даже
если входной итератор разыменовывается в prvalue
в этом случае перемещающее конструирование
не выполняется

См. также

uninitialized_copy
копирует диапазон объектов в неинициализированную область памяти
(шаблон функции и функциональный объект алгоритма)
ranges::uninitialized_copy
(C++20)
uninitialized_move_n
(C++17)
перемещает заданное количество объектов в неинициализированную область памяти
(шаблон функции и функциональный объект алгоритма)
ranges::uninitialized_move_n
(C++20)
ranges::uninitialized_move
(C++20)
перемещает диапазон объектов в неинициализированную область памяти
(функциональный объект алгоритма)

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/memory/uninitialized_move

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API