Standard Library Range Utilities Range Utilities Range Utilities

    standard library algorithm 'distance1' visual example

    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
    
    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)+2begin(v)+7); // int n = 5 // size of entire container auto m = distance(begin(v)end(v)); // int m = 9
    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

    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!

    for_each / for_each_n for_each/for_each_n for_each

    • 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
    standard library algorithm 'ranges-for_each' visual example
    • no out-of-bounds access possible
    #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; });
    standard library algorithm 'for_each' visual example
    • can be used on subranges
    • out-of-bounds access bugs possible
    #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)+2begin(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; });
    standard library algorithm 'for_each_n' visual example
    • can be used on subranges
    • out-of-bounds access bugs possible
    #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; });

    Get Next / Previous Iterator Next/Prev

    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);
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • i
    • i
    • j
    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

    iter_swap iter_swap

    #include <algorithm>
    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) { cout << x <<' '; }  // 0 3 8
    for (int x : w) { cout << x <<' '; }  // 2 1 4 5