std::ranges::destroy_at
| Определено в заголовочном файле <memory>
|
||
| Сигнатура вызова |
||
template< std::destructible T > constexpr void destroy_at( T* p ) noexcept; |
(начиная с C++20) | |
Если T не является типом массива, вызывает деструктор объекта, на который указывает p, как если бы p->~T(). Иначе рекурсивно уничтожает элементы *p по порядку, как если бы вызывом std::destroy(std::begin(*p), std::end(*p)).
Функционально-подобные объекты, описанные на этой странице, являются ниблоидами, то есть:
- Явные списки аргументов шаблона не могут быть указаны при вызове любого из них.
- Ни один из них не виден для поиска, зависящего от аргумента.
- Когда какой-либо из них обнаруживается обычным неквалифицированным поиском по имени слева от оператора вызова функции, поиск, зависящий от аргумента запрещён.
На практике они могут быть реализованы как функциональные объекты или со специальными расширениями компилятора.
Параметры
| p | — | указатель на объект, который нужно уничтожить |
Возвращаемое значение
(нет)
Возможная реализация
struct destroy_at_fn
{
template<std::destructible T>
constexpr void operator()(T *p) const noexcept
{
if constexpr (std::is_array_v<T>)
for (auto &elem : *p)
operator()(std::addressof(elem));
else
p->~T();
}
};
inline constexpr destroy_at_fn destroy_at{};
|
Примечание
destroy_at выводит тип объекта, подлежащего уничтожению, и, следовательно, позволяет избежать его явной записи в вызове деструктора.
Когда destroy_at вызывается при оценке некоторого константного выражения e, аргумент p должен указывать на объект, время жизни которого началось при оценке e.
Пример
В следующем примере показано, как использовать ranges::destroy_at для уничтожения непрерывной последовательности элементов.
#include <iostream>
#include <memory>
#include <new>
struct Tracer
{
int value;
~Tracer() { std::cout << value << " уничтожен\n"; }
};
int main()
{
alignas(Tracer) unsigned char buffer[sizeof(Tracer) * 8];
for (int i = 0; i < 8; ++i)
new(buffer + sizeof(Tracer) * i) Tracer{i}; //создаём объекты вручную
auto ptr = std::launder(reinterpret_cast<Tracer*>(buffer));
for (int i = 0; i < 8; ++i)
std::ranges::destroy_at(ptr + i);
}
Вывод:
0 уничтожен
1 уничтожен
2 уничтожен
3 уничтожен
4 уничтожен
5 уничтожен
6 уничтожен
7 уничтожен
Смотрите также
(C++20) |
уничтожает диапазон объектов (ниблоид) |
(C++20) |
уничтожает несколько объектов в диапазоне (ниблоид) |
(C++20) |
создаёт объект по заданному адресу (ниблоид) |
(C++17) |
уничтожает объект по заданному адресу (шаблон функции) |