std::ranges::uninitialized_value_construct
Материал из cppreference.com
<tbody>
</tbody>
| Определено в заголовочном файле <memory>
|
||
| Сигнатура вызова |
||
template< прямой-итератор-без-исключения I, ограничитель-без-исключения-для<I> S > requires std::default_initializable<std::iter_value_t<I>> I uninitialized_value_construct( I first, S last ); |
(1) | (начиная с C++20) |
template< прямой-диапазон-без-исключения R > requires std::default_initializable<ranges::range_value_t<R>> ranges::borrowed_iterator_t<R> uninitialized_value_construct( R&& r ); |
(2) | (начиная с C++20) |
1) Создаёт объекты типа
std::iter_value_t<I> в неинициализированном хранилище, определяемом диапазоном [first, last), инициализацией значением, как если бы
for (; first != last; ++first)
::new (static_cast<void*>(std::addressof(*first)))
std::remove_reference_t<std::iter_reference_t<I>>();
Если во время инициализации генерируется исключение, уже созданные объекты уничтожаются в неопределённом порядке.
2) То же, что и (1), но использует
r в качестве диапазона, как если бы использовалось ranges::begin(r) в качестве first, и ranges::end(r) в качестве last.Функционально-подобные объекты, описанные на этой странице, являются ниблоидами, то есть:
- Явные списки аргументов шаблона не могут быть указаны при вызове любого из них.
- Ни один из них не виден для поиска, зависящего от аргумента.
- Когда какой-либо из них обнаруживается обычным неквалифицированным поиском по имени слева от оператора вызова функции, поиск, зависящий от аргумента запрещён.
На практике они могут быть реализованы как функциональные объекты или со специальными расширениями компилятора.
Параметры
| first, last | — | пара итератор-ограничитель, обозначающая диапазон элементов для инициализации значением |
| r | — | диапазон элементов для инициализации значением |
Возвращаемое значение
Итератор, равный last.
Сложность
Линейная по расстоянию между first и last.
Исключения
Исключение, генерируемое при создании элементов в целевом диапазоне, если таковые имеются.
Примечание
Реализация может повысить эффективность ranges::uninitialized_value_construct, например используя ranges::fill, если тип значений диапазона TrivialType и CopyAssignable.
Возможная реализация
struct uninitialized_value_construct_fn
{
template<прямой-итератор-без-исключения I, ограничитель-без-исключения-для<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<прямой-диапазон-без-исключения 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 << "Исключение!\n";
}
// Обратите внимание, что для "тривиальных типов" uninitialized_value_construct
// заполняет нулями заданную неинициализированную область памяти.
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
Отчёты о дефектах
Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:
| Номер | Применён | Поведение в стандарте | Корректное поведение |
|---|---|---|---|
| LWG 3870 | C++20 | этот алгоритм может создавать объекты в const хранилище
|
запрещено |
Смотрите также
| создаёт объекты инициализированные значением в неинициализированной области памяти, определяемой началом и количеством (ниблоид) | |
| создаёт объекты инициализацией по умолчанию в неинициализированной области памяти, определяемой диапазоном (ниблоид) | |
| создаёт объекты инициализацией по умолчанию в неинициализированной области памяти, определяемой началом и количеством (ниблоид) | |
| создаёт объекты инициализацией значением в неинициализированной области памяти, определяемой диапазоном (шаблон функции) |