std::ranges::uninitialized_default_construct — cppreference.com
Материал из cppreference.com
<tbody> </tbody>
| Определено в заголовочном файле |
||
| Сигнатура вызова |
||
|
|
(1) | (начиная с C++20) |
|
|
(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.
Исключения
Исключение, генерируемые при создании элементов в целевом диапазоне, если таковые имеются.
Примечание
Реализация может пропустить создание объектов (без изменения наблюдаемого эффекта), если при инициализации по умолчанию объекта std::iter_value_t<I> не вызывается нетривиальный конструктор по умолчанию, который может быть обнаружен std::is_trivially_default_constructible_v.
Возможная реализация
struct uninitialized_default_construct_fn { template<прямой-итератор-без-исключения I, ограничитель-без-исключения-для<I> S> requires std::default_initializable<std::iter_value_t<I>> I operator()(I first, S last) 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, last); // пропустить инициализацию I rollback{first}; try { for (; !(first == last); ++first) ::new (const_cast<void*>(static_cast<const volatile void*> (std::addressof(*first)))) ValueType; 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_default_construct_fn uninitialized_default_construct{};
Пример
#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{first + n}; std::ranges::uninitialized_default_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_default_construct // обычно не заполняет нулями данную неинициализированную область памяти. constexpr char etalon[]{'A', 'B', 'C', 'D', '\n'}; char v[]{'A', 'B', 'C', 'D', '\n'}; std::ranges::uninitialized_default_construct(std::begin(v), std::end(v)); if (std::memcmp(v, etalon, sizeof(v)) == 0) { std::cout << " "; // Возможно неопределённое поведение, вплоть до CWG 1997: // for (const char c : v) { std::cout << c << ' '; } for (const char c : etalon) std::cout << c << ' '; } else std::cout << "Не определено\n"; }
Возможный вывод:
1 ▄▀▄▀▄▀▄▀ 2 ▄▀▄▀▄▀▄▀ 3 ▄▀▄▀▄▀▄▀ 4 ▄▀▄▀▄▀▄▀ A B C D
Отчёты о дефектах
Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:
| Номер | Применён | Поведение в стандарте | Корректное поведение |
|---|---|---|---|
| LWG 3870 | C++20 | этот алгоритм может создавать объекты в const хранилище
|
запрещено |