Standard Library Range Utilities Range Utilities Range Utilities
New to C++'s standard library algorithms? ⇒ Short Introduction
returns the size of an iterator range
distance(@range_begin, @element_in_range)
→ index_of_element_in_range
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator> // std::distance
int main() {
std::vector<int> v {0,1,2,3,4,5,6,7,8};
// size of subrange (as shown in image)
auto n = distance(begin(v)+2, begin(v)+7); // int n = 5
std::cout << "n: " << n << '\n';
// size of entire container
auto m = distance(begin(v), end(v)); // int m = 9
std::cout << "m: " << m << '\n';
std::vector<int> w {4,5,1,9,8};
// get index of smallest element in w:
auto argmin = distance( begin(w), min_element(begin(w),end(w)) );
// int argmin = 2
std::cout << "argmin: " << argmin << '\n';
}
Avoid using distance
with iterators into non-random access
containers like std::list
, because the runtime will be
proportional to the size of the input range!
- convenient if you already have a function(object) to be applied to each element
- works for all standard sequence and associative containers
- container agnostic ⇒ easy to change container type
- no signed/unsigned index type hassle
- self-documenting name
- out-of-bounds access bugs possible with iterator ranges
#include <algorithm> // std::ranges::for_each
namespace ranges = std::ranges; // alias
Container<Type> v; …
// read-only, type cheap to copy or copy needed:
ranges::for_each(v, [](Type x){ cout << x; });
ranges::for_each(v, [](auto x){ cout << x; });
// read-only, type expensive to copy:
ranges::for_each(v, [](Type const& x){ cout << x; });
ranges::for_each(v, [](auto const& x){ cout << x; });
// modify values:
ranges::for_each(v, [](Type& x){ cin >> x; });
ranges::for_each(v, [](auto& x){ cin >> x; });
#include <algorithm> // std::for_each
Container<Type> v; …
// read-only, type cheap to copy or copy needed:
for_each(begin(v), end(v), [](Type x){ cout << x; });
for_each(begin(v)+2, begin(v)+5, [](auto x){ cout << x; });
// read-only, type expensive to copy:
for_each(begin(v), end(v), [](Type const& x){ cout << x; });
for_each(begin(v), end(v), [](auto const& x){ cout << x; });
// modify values:
for_each(begin(v), end(v), [](Type& x){ cin >> x; });
for_each(begin(v), end(v), [](auto& x){ cin >> x; });
#include <algorithm> // std::for_each_n
Container<Type> v; …
auto const n = v.size() / 2;
// read-only, type cheap to copy or copy needed:
for_each_n(begin(v), n, [](Type x){ cout << x; });
// read-only, type expensive to copy:
for_each_n(begin(v), n, [](Type const& x){ cout << x; });
// modify values:
for_each_n(begin(v), n, [](Type& x){ cin >> x; });
#include <iterator>
Functions std::prev
and std::next
provide a universal way of incrementing/decrementing iterators
even if the iterator type does not support random access
(e.g., it += 5
).
However, be aware that advancing non-random access iterators
(e.g., those from std::list
) by N
steps might be
costly, i.e., involve on the order of N
memory operations.
std::vector<int> v {1,2,3,4,5,6};
auto i = next(v.begin());
auto j = next(i, 3);
std::vector<int> v {1,2,3,4,5,6};
auto i = prev(v.end());
i = prev(i);
auto j = prev(i, 3);
- 1
- 2
- 3
- 4
- 5
- 6
-
-
-
-
-
-
- i
-
-
-
-
- i
-
-
- j
-
- i
-
#include <vector>
#include <iostream>
#include <algorithm>
#include <algorithm>
int main () {
std::vector<int> v {0,1,8};
std::vector<int> w {2,3,4,5};
iter_swap(begin(v)+1, begin(w)+1);
for (int x : v) { std::cout << x <<' '; } // 0 3 8
std::cout << '\n';
for (int x : w) { std::cout << x <<' '; } // 2 1 4 5
std::cout << '\n';
}