std::reverse(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

πŸ’– std::reverse(3) β€” bestie, this is the C++ Standard Libary page πŸ’–

Okay so welcome to the glow-up of your range, no cap. This is the manual page for std::reverse(3) in the C++ Standard Libary (yes, spelled like that up top πŸ‘€), and we are gonna keep every detail because that's the whole vibe.


πŸ’– NAME πŸ’–

The name is std::reverse β€” and the one-liner is literally std::reverse - std::reverse. Iconic, honestly. πŸ’…


✨ Synopsis ✨

Defined in header <algorithm> β€” yes bestie, that's the one.

template< class BidirIt >                                (1)
(constexpr since C++20)
void reverse( BidirIt first, BidirIt last );
template< class ExecutionPolicy, class BidirIt >
void reverse( ExecutionPolicy&& policy, BidirIt first,   (2) (since C++17)
BidirIt last );
  1. Reverses the order of the elements in the range [first, last). Behaves as if applying std::iter_swap to every pair of iterators first + i and (last - i) - 1 for each integer i in [0, std::distance(first, last) / 2).
  2. Same as (1), but executed according to policy. This overload participates in overload resolution only if std::is_execution_policy_v<std::decay_t<ExecutionPolicy>> is true. (until C++20) Since C++20, only if std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> is true. (since C++20)
⚠️ If *first is not Swappable (until C++20), or BidirIt is not ValueSwappable (since C++20), the behavior is undefined. That's UB, bestie β€” do not play with it. πŸ’€

πŸŽ€ Parameters πŸŽ€

  • first, last β€” the range of elements to reverse
  • policy β€” the execution policy to use. See execution policy for details.

🧚 Type requirements 🧚

  • BidirIt must meet the requirements of LegacyBidirectionalIterator.

πŸ”₯ Complexity πŸ”₯

Exactly std::distance(first, last) / 2 swaps. That's the whole swap budget, periodt. ✨


πŸ’€ Exceptions πŸ’€

The overload with a template parameter named ExecutionPolicy reports errors as follows:

  • If execution of a function invoked as part of the algorithm throws an exception and ExecutionPolicy is one of the standard policies, std::terminate is called. For any other ExecutionPolicy, the behavior is implementation-defined.
  • If the algorithm fails to allocate memory, std::bad_alloc is thrown.

πŸ› οΈ Possible implementation πŸ› οΈ

See also the implementations in libstdc++, libc++, and MSVC STL.

template<class BidirIt>
constexpr // since C++20
void reverse(BidirIt first, BidirIt last)
{
    using iter_cat = typename std::iterator_traits<BidirIt>::iterator_category;

    // Tag dispatch, e.g. calling reverse_impl(first, last, iter_cat()),
    // can be used in C++14 and earlier modes.
    if constexpr (std::is_base_of_v<std::random_access_iterator_tag, iter_cat>)
    {
        if (first == last)
            return;

        for (--last; first < last; (void)++first, --last)
            std::iter_swap(first, last);
    }
    else
        while (first != last && first != --last)
            std::iter_swap(first++, last);
}

🌸 Notes 🌸

Implementations (e.g. MSVC STL) may enable vectorization when the iterator type satisfies LegacyContiguousIterator and swapping its value type calls neither non-trivial special member function nor ADL-found swap. Fancy vectorized behavior, iykyk. πŸ¦‹


πŸ“ Example πŸ“

// Run this code

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

void println(auto rem, auto const& v)
{
    for (std::cout << rem; auto e : v)
        std::cout << e << ' ';
    std::cout << '\n';
}

int main()
{
    std::vector<int> v {1, 2, 3};
    std::reverse(v.begin(), v.end());
    println("after reverse, v = ", v);

    int a[] = {4, 5, 6, 7};
    std::reverse(std::begin(a), std::end(a));
    println("after reverse, a = ", a);
}

πŸ–¨οΈ Output πŸ–¨οΈ

after reverse, v = 3 2 1
after reverse, a = 7 6 5 4

πŸ› Defect reports πŸ›

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

  • LWG 223 β€” applied to C++98. Behavior as published: std::swap was applied to each pair of iterators. Correct behavior: applies std::iter_swap instead.
  • LWG 2039 β€” applied to C++98. Behavior as published: std::iter_swap was also applied when i equals std::distance(first, last) / 2. Correct behavior: not applied.

πŸ‘€ See also πŸ‘€

  • reverse_copy β€” creates a copy of a range that is reversed (function template)
  • ranges::reverse (C++20) β€” reverses the order of elements in a range (niebloid)

🫢 source/version/date sign-off: http://cppreference.com, 2024.06.10, std::reverse(3) β€” that's the footer, bestie. Bye and slay your ranges! πŸ’…βœ¨
πŸ“¦ where this page comes from