14.6. Basic iterator operations

Iterators in C++ provide pointer-like operations, but their capabilities depend on the iterator category. For example, a list iterator can move forward and backward, while it cannot jump directly to an element by index. The operations in the table are common examples; no iterator is required to support every operation shown.

Common iterator operations

Operation

Result

p == q

True when p and q refer to the same position.

p != q

The negation of p == q.

*p

Refers to the element at the dereferenceable position p.

*p = val

Writes val when p is writable.

val = *p

Reads from the element at p and writes the result to val.

++p

Increments p to the next position.

An iterator must be dereferenceable before *p is used; a past-the-end iterator such as end() is not dereferenceable. Incrementing a past-the-end iterator is invalid. Comparing iterators from different sequences is also generally invalid, so compare iterators that belong to the same sequence.

14.6.1. Legacy iterator categories and C++20 concepts

Different containers need different capabilities from their iterators.

The older C++ standard describes iterator capabilities using named requirements. C++20 also provides concepts with corresponding names, such as std::forward_iterator and std::contiguous_iterator. In both models, the required operations determine what an iterator can do; the iterator does not need to inherit from a base class.

The traversal capabilities form a hierarchy:

input -> forward -> bidirectional -> random access -> contiguous

Each category on the right supports the operations of the categories on its left. Output capability is separate. An iterator can support both traversal and output, such as a mutable vector iterator, but an output iterator does not have to support reading or multipass traversal.

In the diagram, solid arrows show the traversal hierarchy. Dotted lines show that output capability can be combined with any traversal capability.

Iterator categories

Input Iterator

Reads elements and advances using operator++. It supports only single-pass traversal, so an iterator copy is not expected to remain independently usable after one copy advances. std::istream_iterator is an example.

Forward Iterator

InputIterator, plus default construction, equality comparison, and multipass traversal. Copies of a forward iterator can be advanced independently. The forward_list container provides this iterator.

Bidirectional Iterator

ForwardIterator, plus pre-increment and post-increment using operator++ and pre-decrement and post-decrement using operator--. Containers like list, map, and set provide this iterator.

Random Access Iterator

BidirectionalIterator, plus constant-time jumps using operator+=, operator-=, operator+, operator-, and operator[]. Containers like vector, deque, array, and string provide random-access iterators. Unordered associative containers do not.

Contiguous Iterator

RandomAccessIterator, plus a guarantee that the elements occupy one contiguous range of storage. The category was added to standard terminology in C++17, and C++20 provides the std::contiguous_iterator concept. It formalizes the guarantee already provided by containers such as vector, array, and string.

Output Iterator

A separate capability that allows writing through dereference. An output iterator does not have to support reading, equality comparison, or multipass traversal. In modern C++, this capability is described by the std::output_iterator concept.

The following example uses a back-inserting output iterator. Dereferencing it is valid on the left-hand side of an assignment, but it is not used to read a value:

 1#include <iostream>
 2#include <iterator>
 3#include <vector>
 4
 5int main() {
 6  std::vector<int> values;
 7  auto output = std::back_inserter(values);
 8
 9  *output = 10;
10  ++output;
11  *output = 20;
12
13  for (const auto value : values) {
14    std::cout << value << ' ';
15  }
16  std::cout << '\n';
17}

More to Explore