std::ranges::uninitialized_copy, std::ranges::uninitialized_copy_result
Материал из cppreference.com
<tbody>
</tbody>
| Определено в заголовочном файле <memory>
|
||
| Сигнатура вызова |
||
template< std::input_iterator I, std::sentinel_for<I> S1, прямой-итератор-без-исключения O, ограничитель-без-исключения-для<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, прямой-диапазон-без-исключения 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) Пусть N будет
ranges::min(ranges::distance(ifirst, ilast), ranges::distance(ofirst, olast)), создаёт элементы N в выходном диапазоне [ofirst, olast), который является неинициализированной областью памяти, из элементов во входном диапазоне [ifirst, ilast). Входные и выходные диапазоны не должны перекрываться.
Если во время инициализации генерируется исключение, уже созданные объекты уничтожаются в неопределённом порядке.
Функция имеет эффект, эквивалентный:
for (; !(ifirst == ilast || ofirst == olast); ++ofirst, ++ifirst)
{
::new (static_cast<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.Функционально-подобные объекты, описанные на этой странице, являются ниблоидами, то есть:
- Явные списки аргументов шаблона не могут быть указаны при вызове любого из них.
- Ни один из них не виден для поиска, зависящего от аргумента.
- Когда какой-либо из них обнаруживается обычным неквалифицированным поиском по имени слева от оператора вызова функции, поиск, зависящий от аргумента запрещён.
На практике они могут быть реализованы как функциональные объекты или со специальными расширениями компилятора.
Параметры
| ifirst, ilast | — | пара итераторов ограничителей, обозначающая диапазон элементов, из которого следует копировать |
| in_range | — | диапазон элементов для копирования |
| ofirst, olast | — | пара итераторов ограничителей, обозначающая диапазон назначения |
| out_range | — | диапазон назначения |
Возвращаемое значение
{ifirst + N, ofirst + N}.
Сложность
𝓞(N).
Исключения
Исключение, возникающее при построении элементов в целевом диапазоне, если таковые имеются.
Примечание
Реализация может повысить эффективность ranges::uninitialized_copy, если тип значения выходного диапазона TrivialType.
Возможная реализация
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[]{ "Это", "пример", };
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 << (it == first ? "" : ", ") << std::quoted(*it);
std::cout << "};\n";
std::ranges::destroy(first, last);
}
catch (...)
{
std::cout << "исключение uninitialized_copy\n";
}
std::free(pbuf);
}
}
Вывод:
{ "Это", "пример" };
Отчёты о дефектах
Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:
| Номер | Применён | Поведение в стандарте | Корректное поведение |
|---|---|---|---|
| LWG 3870 | C++20 | этот алгоритм может создавать объекты в const хранилище
|
запрещено |
Смотрите также
(C++20) |
копирует ряд объектов в неинициализированную область памяти (ниблоид) |
| копирует диапазон объектов в неинициализированную область памяти (шаблон функции) |