# std::ranges::uninitialized_value_construct

< cpp‎ | memory

定义于头文件 `<memory>` |  |
调用签名 |  |
template <no-throw-forward-iterator I, no-throw-sentinel-for<I> S> requires std::default_initializable<std::iter_value_t<I>> I uninitialized_value_construct( I first, S last ); | (1) | (C++20 起)
template <no-throw-forward-range R> requires std::default_initializable<ranges::range_value_t<R>> ranges::borrowed_iterator_t<R> uninitialized_value_construct( R&& r ); | (2) | (C++20 起)

1) 以值初始化在范围 `[first, last)` 所指代的未初始化存储中构造 std::iter_value_t<I> 类型对象，如同用

    for (; first != last; ++first)
      ::new (const_cast<void*>(static_cast<const volatile void*>(std::addressof(*first))))
        std::remove_reference_t<std::iter_reference_t<I>>();

若初始化期间抛出异常，则按未指定顺序销毁已构造的对象。
2) 同 (1) ，但以 `r` 为迭代器，如同以 ranges::begin(r) 为 `first` 并以 ranges::end(r) 为 `last` 。

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

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

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

### 参数

first, last | - | 要值初始化的元素范围
r | - | 要值初始化的元素范围

### 返回值

等于 `last` 的迭代器。

### 复杂度

与 `first` 和 `last` 间的距离成线性。

### 异常

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

### 注解

若范围的值类型为平凡类型 (TrivialType) 及可复制赋值 (CopyAssignable) ，则实现可以提升 `ranges::uninitialized_value_construct` 的效率，例如用 ranges::fill 。

### 可能的实现

    struct uninitialized_value_construct_fn {
        template <no-throw-forward-iterator I, no-throw-sentinel-for<I> S>
        requires std::default_initializable<std::iter_value_t<I>>
        I operator()( I first, S last ) const {
            using T = std::remove_reference_t<std::iter_reference_t<I>>;
            if constexpr (std::is_trivial_v<T> && std::is_copy_assignable_v<T>)
                return ranges::fill(first, last, T());
            I rollback {first};
            try {
                for (; !(first == last); ++first)
                    ::new (const_cast<void*>(static_cast<const volatile void*>
                            (std::addressof(*first)))) T();
                return first;
            } catch (...) { // 回滚：销毁已构造的元素
                for (; rollback != first; ++rollback)
                    ranges::destroy_at(std::addressof(*rollback));
                throw;
            }
        }

        template <no-throw-forward-range R>
        requires std::default_initializable<ranges::range_value_t<R>>
        ranges::borrowed_iterator_t<R>
        operator()( R&& r ) const {
            return (*this)(ranges::begin(r), ranges::end(r));
        }
    };

    inline constexpr uninitialized_value_construct_fn uninitialized_value_construct{};

### 示例

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

    int main()
    {
        struct S { std::string m{ "▄▀▄▀▄▀▄▀" }; };

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

        try
        {
            auto first {reinterpret_cast<S*>(out)};
            auto last {first + n};

            std::ranges::uninitialized_value_construct(first, last);

            auto count {1};
            for (auto it {first}; it != last; ++it) {
                std::cout << count++ << ' ' << it->m << '\n';
            }

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

        // Notice that for "trivial types" the uninitialized_value_construct
        // zero-fills the given uninitialized memory area.
        int v[] { 0, 1, 2, 3 };
        std::cout << ' ';
        for (const int i : v) { std::cout << ' ' << static_cast<char>(i + 'A'); }
        std::cout << "\n ";
        std::ranges::uninitialized_value_construct(std::begin(v), std::end(v));
        for (const int i : v) { std::cout << ' ' << static_cast<char>(i + 'A'); }
        std::cout << '\n';
    }

输出：

    1 ▄▀▄▀▄▀▄▀
    2 ▄▀▄▀▄▀▄▀
    3 ▄▀▄▀▄▀▄▀
    4 ▄▀▄▀▄▀▄▀
      A B C D
      A A A A

### 参阅

ranges::uninitialized_value_construct_n (C++20) | 在起始与计数所定义的未初始化的内存区域以值初始化构造对象 (niebloid)
ranges::uninitialized_default_construct (C++20) | 在范围所定义的未初始化的内存区域以默认初始化构造对象 (niebloid)
ranges::uninitialized_default_construct_n (C++20) | 在起始与计数所定义的未初始化的内存区域以默认初始化构造对象 (niebloid)
uninitialized_value_construct (C++17) | 在范围所定义的未初始化内存中用值初始化构造对象 (函数模板)