# std::ranges::uninitialized_copy_n, std::ranges::uninitialized_copy_n_result

< cpp‎ | memory

定义于头文件 `<memory>` |  |
调用签名 |  |
template< std::input_iterator I, no-throw-input-iterator O, no-throw-sentinel-for<O> S > requires std::constructible_from<std::iter_value_t<O>, std::iter_reference_t<I>> uninitialized_copy_n_result<I, O> uninitialized_copy_n( I ifirst, std::iter_difference_t<I> count, O ofirst, S olast ); | (1) | (C++20 起)
辅助类型 |  |
template<class I, class O> using uninitialized_copy_n_result = ranges::in_out_result<I, O>; | (2) | (C++20 起)

令 \(\scriptsize N\)N 为 ranges::min(count, ranges::distance(ofirst, olast)) ，以始于 `ifirst` 的输入范围的元素为来源，在作为未初始化内存区域的输出范围 `[ofirst, olast)` 中构造 \(\scriptsize N\)N 个元素。

输入范围 `[ifirst, ifirst + count)` 必须不与输出范围 `[ofirst, olast)` 重叠。

若在初始化期间抛异常，则以未指定顺序销毁已构造的元素。

函数所拥有的效果等价于：

    auto ret = ranges::uninitialized_copy(std::counted_iterator(ifirst, count),
                                          std::default_sentinel, ofirst, olast);
    return {std::move(ret.in).base(), ret.out};

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

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

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

### 参数

ifirst | - | 要复制的元素范围的起始
count | - | 要复制的元素数
ofirst, olast | - | 目标范围

### 返回值

{ifirst + N, ofirst + N} 。

### 复杂度

\(\scriptsize\mathcal{O}(N)\)𝓞(N) 。

### 异常

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

### 注解

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

### 可能的实现

    struct uninitialized_copy_n_fn {
        template <std::input_iterator I, no-throw-input-iterator O, no-throw-sentinel-for<O> S>
        requires std::constructible_from<std::iter_value_t<O>, std::iter_reference_t<I>>
        ranges::uninitialized_copy_n_result<I, O>
        operator()( I ifirst, std::iter_difference_t<I> count, O ofirst, S olast ) const {
            O current {ofirst};
            try {
                for (; count > 0 && current != olast; ++ifirst, ++current, --count)
                    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;
            }
        }
    };

    inline constexpr uninitialized_copy_n_fn uninitialized_copy_n{};

### 示例

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

    int main()
    {
        const char* stars[] { "Procyon", "Spica", "Pollux", "Deneb", "Polaris", };

        constexpr int n {4};
        alignas(alignof(std::string)) char out[n * sizeof(std::string)];

        try
        {
            auto first {reinterpret_cast<std::string*>(out)};
            auto last {first + n};
            auto ret {std::ranges::uninitialized_copy_n(std::begin(stars), n, first, last)};

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

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

输出：

    { "Procyon", "Spica", "Pollux", "Deneb", };

### 参阅

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