Skip to main content

std::ranges::destroy() algorithm

// (1)
constexpr I destroy( I first, S last ) noexcept;

// (2)
constexpr ranges::borrowed_iterator_t<R> destroy( R&& r ) noexcept;

The type of arguments are generic and have following constraints:

  • I - no-throw-input-iterator
  • S - no-throw-sentinel-for<O>
  • R - no-throw-input-range

Additionally, each overload has the following constraints:

  • (1) std::destructible<std::iter_value_t<I>>
  • (1) std::destructible<ranges::range_value_t<R>>
  • (1) Destroys the objects in the range [first; last), as if by

    for (; first != last; ++first)
    std::ranges::destroy_at(std::addressof(*first));

    return first;
    caution

    If an exception is thrown during the initialization then the objects that already constructed in [ofirst; olast) are destroyed in an unspecified order.

    Also, the objects in [ifirst; ilast) that were already moved, are left in a valid but unspecified state.

  • (2) Same as (1), but uses in_range as the first range and out_range as the second range, as if using ranges::begin(in_range) as ifirst, ranges::end(in_range) as ilast, ranges::begin(out_range) as ofirst, and ranges::end(out_range) as olast.

The function-like entities described on this page are niebloids.

Parameters

first
last

The range of elements to destroy.

r

The range of elements to destroy.

Return value

An iterator compares equal to last.

Complexity

Linear in the distance between first and last.

Exceptions

The exception thrown on construction of the elements in the destination range, if any.

Possible implementation

destroy(1) and destroy(2)
struct destroy_fn
{
template<no-throw-input-iterator I, no-throw-sentinel-for<I> S>
requires std::destructible<std::iter_value_t<I>>
constexpr I operator()(I first, S last) const noexcept
{
for (; first != last; ++first)
std::ranges::destroy_at(std::addressof(*first));
return first;
}

template<no-throw-input-range R>
requires std::destructible<std::ranges::range_value_t<R>>
constexpr std::ranges::borrowed_iterator_t<R> operator()(R&& r) const noexcept
{
return operator()(std::ranges::begin(r), std::ranges::end(r));
}
};

inline constexpr destroy_fn destroy{};

Examples

Main.cpp
#include <iostream>
#include <memory>
#include <new>

struct Tracer
{
int value;
~Tracer() { std::cout << value << " destructed\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}; //manually construct objects

auto ptr = std::launder(reinterpret_cast<Tracer*>(buffer));

std::ranges::destroy(ptr, ptr + 8);
}
Output
0 destructed
1 destructed
2 destructed
3 destructed
4 destructed
5 destructed
6 destructed
7 destructed
This article originates from this CppReference page. It was likely altered for improvements or editors' preference. Click "Edit this page" to see all changes made to this document.
Hover to see the original license.

std::ranges::destroy() algorithm

// (1)
constexpr I destroy( I first, S last ) noexcept;

// (2)
constexpr ranges::borrowed_iterator_t<R> destroy( R&& r ) noexcept;

The type of arguments are generic and have following constraints:

  • I - no-throw-input-iterator
  • S - no-throw-sentinel-for<O>
  • R - no-throw-input-range

Additionally, each overload has the following constraints:

  • (1) std::destructible<std::iter_value_t<I>>
  • (1) std::destructible<ranges::range_value_t<R>>
  • (1) Destroys the objects in the range [first; last), as if by

    for (; first != last; ++first)
    std::ranges::destroy_at(std::addressof(*first));

    return first;
    caution

    If an exception is thrown during the initialization then the objects that already constructed in [ofirst; olast) are destroyed in an unspecified order.

    Also, the objects in [ifirst; ilast) that were already moved, are left in a valid but unspecified state.

  • (2) Same as (1), but uses in_range as the first range and out_range as the second range, as if using ranges::begin(in_range) as ifirst, ranges::end(in_range) as ilast, ranges::begin(out_range) as ofirst, and ranges::end(out_range) as olast.

The function-like entities described on this page are niebloids.

Parameters

first
last

The range of elements to destroy.

r

The range of elements to destroy.

Return value

An iterator compares equal to last.

Complexity

Linear in the distance between first and last.

Exceptions

The exception thrown on construction of the elements in the destination range, if any.

Possible implementation

destroy(1) and destroy(2)
struct destroy_fn
{
template<no-throw-input-iterator I, no-throw-sentinel-for<I> S>
requires std::destructible<std::iter_value_t<I>>
constexpr I operator()(I first, S last) const noexcept
{
for (; first != last; ++first)
std::ranges::destroy_at(std::addressof(*first));
return first;
}

template<no-throw-input-range R>
requires std::destructible<std::ranges::range_value_t<R>>
constexpr std::ranges::borrowed_iterator_t<R> operator()(R&& r) const noexcept
{
return operator()(std::ranges::begin(r), std::ranges::end(r));
}
};

inline constexpr destroy_fn destroy{};

Examples

Main.cpp
#include <iostream>
#include <memory>
#include <new>

struct Tracer
{
int value;
~Tracer() { std::cout << value << " destructed\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}; //manually construct objects

auto ptr = std::launder(reinterpret_cast<Tracer*>(buffer));

std::ranges::destroy(ptr, ptr + 8);
}
Output
0 destructed
1 destructed
2 destructed
3 destructed
4 destructed
5 destructed
6 destructed
7 destructed
This article originates from this CppReference page. It was likely altered for improvements or editors' preference. Click "Edit this page" to see all changes made to this document.
Hover to see the original license.