# std::ranges::uninitialized_copy, std::ranges::uninitialized_copy_result

< cpp‎ | memory

定义于头文件 `<memory>` |  |
调用签名 |  |
template< std::input_iterator I, std::sentinel_for<I> S1, no-throw-forward-iterator O, no-throw-sentinel-for<O> S2 > requires std::constructible_from<std::iter_value_t<O>, std::iter_reference_t<I>> uninitialized_copy_result<I, O> uninitialized_copy( I ifirst, S1 ilast, O ofirst, S2 olast ); | (1) | (C++20 起)
template< ranges::input_range IR, no-throw-forward-range OR > requires std::constructible_from<ranges::range_value_t<OR>, ranges::range_reference_t<IR>> uninitialized_copy_result<ranges::borrowed_iterator_t<IR>, ranges::borrowed_iterator_t<OR>> uninitialized_copy( IR&& in_range, OR&& out_range ); | (2) | (C++20 起)
辅助类型 |  |
template<class I, class O> using uninitialized_copy_result = ranges::in_out_result<I, O>; | (3) | (C++20 起)

1) 令 \(\scriptsize N\)N 为 ranges::min(ranges::distance(ifirst, ilast), ranges::distance(ofirst, olast)) ，在作为未初始化内存区域的输出范围 `[ofirst, olast)` 中，以输入范围 `[ifirst, ilast)` 中的元素为来源构造 \(\scriptsize N\)N 个元素。
输入与输出范围必须不重叠。
若在初始化时抛异常，则以未指定顺序销毁已构造的元素。
函数拥有的效果等价于：

    for (; !(ifirst == ilast || ofirst == olast); ++ofirst, ++ifirst) {
        ::new (const_cast<void*>(static_cast<const volatile void*>(std::addressof(*ofirst))))
            std::remove_reference_t<std::iter_reference_t<O>>(*ifirst);
    }

2) 同 (1) ，但以 `in_range` 为第一范围并以 `out_range` 为第二范围，如同以 ranges::begin(in_range) 为 `ifirst` ，以 ranges::end(in_range) 为 `ilast` ，以 ranges::begin(out_range) 为 `ofirst` ，并以 ranges::end(out_range) 为 `olast` 。

此页面上描述的仿函数实体是 niebloid ，即：

- 调用它们中的任何一者时不可指定显式模板实参。
- 它们无一对实参依赖查找可见。
- 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

### 参数

ifirst, ilast | - | 要复制的元素范围
in_range | - | 要复制的元素范围
ofirst, olast | - | 目标范围
out_range | - | 目标范围

### 返回值

{ifirst + N, ofirst + N} 。

### 复杂度

O(N)𝓞(N) 。

### 异常

构造目标范围中的元素时抛出的异常，若存在。

### 注解

若输出范围的值类型为平凡类型 (TrivialType) ，则实现可能提升 `ranges::uninitialized_copy` 的效率。

### 可能的实现

    struct uninitialized_copy_fn {
        template <std::input_iterator I, std::sentinel_for<I> S1,
                 no-throw-forward-iterator O, no-throw-sentinel-for<O> S2>
        requires std::constructible_from<std::iter_value_t<O>, std::iter_reference_t<I>>
        ranges::uninitialized_copy_result<I, O>
        operator()( I ifirst, S1 ilast, O ofirst, S2 olast ) const {
            O current {ofirst};
            try {
                for (; !(ifirst == ilast or current == olast); ++ifirst, ++current)
                    ranges::construct_at(std::addressof(*current), *ifirst);
                return {std::move(ifirst), std::move(current)};
            } catch (...) { // 回滚：销毁构造的元素
                for (; ofirst != current; ++ofirst)
                    ranges::destroy_at(std::addressof(*ofirst));
                throw;
            }
        }

        template <ranges::input_range IR, no-throw-forward-range OR>
        requires std::constructible_from<ranges::range_value_t<OR>,
                 ranges::range_reference_t<IR>>
        ranges::uninitialized_copy_result<ranges::borrowed_iterator_t<IR>,
                 ranges::borrowed_iterator_t<OR>>
        operator()( IR&& in_range, OR&& out_range ) const {
            return (*this)(ranges::begin(in_range), ranges::end(in_range),
                           ranges::begin(out_range), ranges::end(out_range));
        }
    };

    inline constexpr uninitialized_copy_fn uninitialized_copy{};

### 示例

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

    int main()
    {
        const char* v[] { "This", "is", "an", "example", };

        if (const auto sz{std::size(v)};
            void* pbuf = std::aligned_alloc(alignof(std::string), sizeof(std::string) * sz))
        {
            try
            {
                auto first {static_cast<std::string*>(pbuf)};
                auto last {first + sz};
                std::ranges::uninitialized_copy(std::begin(v), std::end(v), first, last);

                std::cout << "{ ";
                for (auto it {first}; it != last; ++it)
                    std::cout << std::quoted(*it) << ", ";
                std::cout << "};\n";

                std::ranges::destroy(first, last);
            }
            catch(...)
            {
                std::cout << "uninitialized_copy exception\n";
            }
            std::free(pbuf);
        }
    }

输出：

    { "This", "is", "an", "example", };

### 参阅

ranges::uninitialized_copy_n (C++20) | 复制一定量元素到未初始化的内存区域 (niebloid)
uninitialized_copy | 将范围内的对象复制到未初始化的内存区域 (函数模板)