std::ranges::uninitialized_default_construct
Определено в заголовочном файле <memory>
|
||
Сигнатура вызова |
||
template< прямой-итератор-без-исключения I, ограничитель-без-исключения-для<I> S > requires std::default_initializable<std::iter_value_t<I>> |
(1) | (начиная с C++20) |
template< прямой-диапазон-без-исключения R > requires std::default_initializable<ranges::range_value_t<R>> |
(2) | (начиная с C++20) |
[
first,
last)
инициализацией по умолчанию, как если бы
for (; first != last; ++first) ::new (static_cast<void*>(std::addressof(*first))) std::remove_reference_t<std::iter_reference_t<I>>;
Функционально-подобные объекты, описанные на этой странице, являются ниблоидами, то есть:
- Явные списки аргументов шаблона не могут быть указаны при вызове любого из них.
- Ни один из них не виден для поиска, зависящего от аргумента.
- Когда какой-либо из них обнаруживается обычным неквалифицированным поиском по имени слева от оператора вызова функции, поиск, зависящий от аргумента запрещён.
На практике они могут быть реализованы как функциональные объекты или со специальными расширениями компилятора.
Содержание |
[править] Параметры
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 хранилище | запрещено |
[править] Смотрите также
создаёт объекты инициализацией по умолчанию в неинициализированной области памяти, определяемой началом и количеством (ниблоид) | |
создаёт объекты инициализацией значением в неинициализированной области памяти, определяемой диапазоном (ниблоид) | |
создаёт объекты инициализированные значением в неинициализированной области памяти, определяемой началом и количеством (ниблоид) | |
создаёт объекты инициализацией по умолчанию в неинициализированной области памяти, определяемой диапазоном (шаблон функции) |