Iterators

Iterators a pointer-like types that we can use to traverse containers without caring about the underlying structure.

Containers provide their own iterators which implement the iterator interface. We can get two special iterators, begin(), which points to the first element in the container and end(), which point past the last element in the container. The end iterator is not meant to be dereferenced.

std::vector<int> ints {1, 2, 3, 4, 5};
std::vector<int>::iterator it = ints.begin();
std::vector<int>::iterator end_it = ints.end();

std::cout << *it << std::endl;
++it;
*it = 99;
std::cout << *it << <<std::endl
std::cout << (it == end_it) << std::endl;

We can process subsets of a collection by adding and subtracting an offset to our iterators, For example begin() + 3 and end() – 2. For example:

#include <iostream>
#include <string>
#include <vector>

template <typename T>
void print_collection(T collection, int begin_offset = 0, int end_offset = 0) {
    auto current_it = collection.begin() + begin_offset;
    auto end_it = collection.end() - end_offset;

    std::cout << "[ ";

    while (current_it != end_it) {
        std::cout << *current_it << " ";
        ++current_it;
    }

    std::cout << "]" << std::endl;
}

int main() {
    std::vector<int> ints {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    print_collection(ints);
    print_collection(ints, 2, 3);


    return 0;
}

Collections can be iterated backwards by using reverse iterators. To do this we use the rbegin() and rend() methods. Rbegin points to the last element in the collection and rend points past the first. Counter-intuitively, e move backwards by incrementing the reverse iterator rather than decrementing it. We can’t compare reverse iterators to forward iterators.

By default we can use iterators to modify data, to prevent this we can use constant iterators with cbegin() and cend(). Apart from blocking modification, they work the same as normal iterators. There are also constant reverse iterators which we can use with crbegin() and crend().

There are different types of iterator. input and output, forward, bi-directional, and random access.  In C++20, we have contiguous iterators which guarantee data is in contiguous memory.

Instead of the begin and end methods we can also use the std::begin() and std::end() function to get iterators. As well as STL collections, these can handle raw arrays.

Read more on iterators.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.