std::ranges::uninitialized_default_construct_n
Определено в заголовке <memory> | ||
|---|---|---|
| Подпись вызова | ||
template< no-throw-forward-iterator I > requires std::default_initializable<std::iter_value_t<I>> I uninitialized_default_construct_n( I first, std::iter_difference_t<I> n ); | (с C++20) |
Конструирует объекты типа std::iter_value_t<I> в области памяти, не инициализированной, начиная с first, с помощью неявной инициализации, как если бы
for (; n-- > 0; ++first)
::new (static_cast<void*>(std::addressof(*first)))
std::remove_reference_t<std::iter_reference_t<I>>;Если во время инициализации происходит исключение, уже построенные объекты уничтожаются в неопределенном порядке.
Функциональные сущности, описанные на этой странице, являются неблоидами, то есть:
- Явные списки шаблонов аргументов не могут быть указаны при вызове ни одного из них.
- Ни один из них не виден для поиска зависимого от аргумента.
- Когда любой из них находится с помощью обычного поиска без квалификаторов в качестве имени слева от оператора вызова функции, поиск зависимого от аргумента запрещен.
На практике они могут быть реализованы как объекты функций или с помощью специальных расширений компилятора.
Параметры
| first | - | начало диапазона элементов для инициализации |
| n | - | количество элементов для построения |
Возвращаемое значение
Конец диапазона объектов (т.е., ranges::next(first, n)).
Сложность
Линейная по отношению к n.
Исключение
Исключение, сгенерированное при построении элементов в целевом диапазоне, если таковое имеется.
Примечания
Реализация может пропустить построение объектов (без изменения наблюдаемого эффекта), если при неявной инициализации объекта типа std::iter_value_t<I> не вызывается никакой нетривиальный конструктор по умолчанию, что можно обнаружить с помощью std::is_trivially_default_constructible_v.
Возможная реализация
struct uninitialized_default_construct_n_fn
{
template<no-throw-forward-iterator I>
requires std::default_initializable<std::iter_value_t<I>>
I operator()(I first, std::iter_difference_t<I> n) const
{
using ValueType = std::remove_reference_t<std::iter_reference_t<I>>;
if constexpr (std::is_trivially_default_constructible_v<ValueType>)
return ranges::next(first, n); // skip initialization
I rollback{first};
try
{
for (; n-- > 0; ++first)
::new (const_cast<void*>(static_cast<const volatile void*>
(std::addressof(*first)))) ValueType;
return first;
}
catch (...) // rollback: destroy constructed elements
{
for (; rollback != first; ++rollback)
ranges::destroy_at(std::addressof(*rollback));
throw;
}
}
};
inline constexpr uninitialized_default_construct_n_fn uninitialized_default_construct_n{}; |
Пример
#include <cstring>
#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 = std::ranges::uninitialized_default_construct_n(first, n);
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_default_construct_n
// generally does not zero-fill the given uninitialized memory area.
constexpr int etalon[]{1, 2, 3, 4, 5, 6};
int v[]{1, 2, 3, 4, 5, 6};
std::ranges::uninitialized_default_construct_n(std::begin(v), std::size(v));
if (std::memcmp(v, etalon, sizeof(v)) == 0)
{
// Maybe undefined behavior, pending CWG 1997:
// for (const int i : v) { std::cout << i << ' '; }
for (const int i : etalon)
std::cout << i << ' ';
}
else
std::cout << "Unspecified!";
std::cout << '\n';
}Возможный вывод:
1 █▓▒░ █▓▒░ 2 █▓▒░ █▓▒░ 3 █▓▒░ █▓▒░ 4 █▓▒░ █▓▒░ 1 2 3 4 5 6
Отчеты об ошибках
Следующие отчеты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применено к | Поведение при публикации | Корректное поведение |
|---|---|---|---|
| LWG 3870 | C++20 | Этот алгоритм может создавать объекты в const хранилище | оставлено запрещенным |
См. также
|
(C++20) | конструирует объекты с помощью неявной инициализации в неинициализированной области памяти, определенной диапазоном (неблоид) |
|
(C++20) | конструирует объекты с явной инициализацией в неинициализированной области памяти, определенной диапазоном (неблоид) |
|
(C++20) | конструирует объекты с явной инициализацией в неинициализированной области памяти, определенной началом и количеством (неблоид) |
|
(C++17) | конструирует объекты с помощью неявной инициализации в неинициализированной области памяти, определенной началом и количеством (шаблон функции) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/memory/ranges/uninitialized_default_construct_n