Concepts / Iterator Concept and Shared Semantics

Iterator Concept and Shared Semantics

Iterator types differ because each iterator must hold the information needed to do its job for a particular container type.

  • Programming

The Visiting Question

Suppose you have a collection of values and want to visit each one in turn. Whatever is doing the visiting has to keep track of where it currently is. That tracking object is an iterator. Visiting a collection is a simple idea, but it raises a question that is worth working through slowly: do two different kinds of collection need the same information to be visited?

What do you think happens?

One collection stores its values in a contiguous run of slots, and the other stores them as a chain of linked pieces. Does the visiting object need the same information to walk both?

  • Yes, the visitor always needs exactly the same information

  • No, the information needed depends on how the collection is organized

Reveal answer
Answer:

No, the information needed depends on how the collection is organized.

An iterator has to hold whatever information it needs to do its job for one particular kind of container. Information that is enough for one container may be useless for another, which is why iterator types can differ as much as the containers themselves.

The rest of this article follows that question. We will trace what a visitor must remember for a vector, then for a list, and see how the answer shapes the iterator type. Along the way we will find the small set of behaviors that every iterator shares, and how a container advertises its iterator types so that general code can refer to them by name.

Tracing a Visitor Through a Vector

Start with the vector, a container whose elements sit in order and can be reached by position. Its elements occupy a contiguous run of slots, so each element sits next to its neighbor in a predictable place. A vector iterator has a simple option available: it can be an ordinary pointer to an element. A pointer is a reasonable way to refer to an element of a vector, so no extra machinery is needed. Holding that one pointer is enough to know where you are and to step forward to the neighboring element.

Slot 0first valueSlot 1second valueSlot 2third valuenext slotnext slot
In a vector, each element occupies a numbered slot next to its neighbor, so stepping forward is a matter of moving to the next slot.

The vector iterator could also be designed differently. Instead of holding only a pointer, it could hold a pointer to the vector itself together with an index, which is a number giving the position within that vector. Both designs are valid for a vector, but they carry different information. The second design is the one that would allow range checking, meaning the iterator can judge whether a requested position actually falls within the vector. So even for one container, the choice of what to remember changes what the iterator is able to do.

Why a List Iterator Needs More

Now turn to the list. A list element cannot be relied on to know where the next element is. Each element is simply a value in its own place, and the link to its neighbor is not something the element itself is guaranteed to carry for the iterator's purposes. Because of this, a pointer to an element is not enough to move from one list element to the next. Holding the element's location tells you where the value is, but gives no route onward.

The list iterator therefore has to be something more complicated than a simple pointer to an element. One natural choice is a pointer to a link, meaning the iterator refers to the connecting piece of the list rather than to the bare element. From the link, the iterator can reach the element it refers to and also the link that leads onward. This is the reason the list iterator and the vector iterator end up with different types, even though both serve the same purpose of visiting values.

Vector iteratorElement pointerVector pointer andindexList iteratorLink pointeroption oneoption twoholds
A vector iterator can hold a single element pointer, or a vector pointer plus an index. A list iterator holds a pointer to a link, which gives access to both the element and the onward link.

Stepping a List Iterator Forward

Trace what happens when a list iterator moves. It holds a link. Advancing it means following the link to the next piece of the list, so the iterator now refers to that next link and, through it, the next element. The diagram below shows three links in a chain. The iterator starts on the first link, and after one increment it refers to the second.

Link Avalue 10Link Bvalue 20Link Cvalue 30follow next linkfollow next link
Incrementing the iterator follows the link from its current piece to the next piece, so the iterator's position moves from the first link to the second.
Worked example

One increment on a three-link list

A list iterator refers to Link A, which holds the value 10. Link B holds 20 and Link C holds 30. The increment operator is applied once, and then the value is read through the dereference operator.

  1. 1
    Starting position

    The iterator refers to Link A, so it refers to the element holding 10.

  2. 2
    Apply the increment

    Incrementing follows the onward link from Link A to Link B. The iterator now refers to Link B.

  3. 3
    Apply the dereference

    Dereferencing the iterator yields the element it now refers to, which holds 20.

Result

After one increment, the iterator refers to the element holding 20.

Operations Every Iterator Shares

After seeing how varied the designs are, it may seem that every iterator is a different creature. The source emphasizes the opposite. What is common to all iterators is their semantics and the naming of their operations. Two operations do most of the work. Applying the increment operator, written ++, to any iterator yields an iterator that refers to the next element. Applying the dereference operator, which is written as an asterisk, yields the element to which the iterator refers.

AspectVector iteratorList iterator
Typical internal choiceA pointer to an element, or a pointer to the vector plus an indexA pointer to a link
Does ++ move to the next element?Yes, by stepping to the neighboring elementYes, by following the onward link
Does the dereference operator yield the element?YesYes
Why it differsElements are reachable by position in a contiguous runElements do not know where the next one is, so a link is needed

Different internals, same external operations

This is why one idea can cover all of these types. Any object that obeys a few simple rules like these counts as an iterator, and that shared set of rules is what the concept of an iterator describes. The internal representation can vary widely, but the behavior seen from outside stays consistent. A reader who knows the operations can use an iterator without knowing how it was built.

Naming Iterator Types Through the Container

A natural follow-up question is how a programmer refers to these types without memorizing their details. The source notes that users rarely need to know the specific type of a particular iterator. Instead, each container knows its own iterator types and makes them available under the conventional names iterator and const_iterator. The names are the same across containers, even though the types behind them are not.

Definition

The conventional name iterator, written after a container name, refers to that container's general iterator type. For example, list<Entry>::iterator is the general iterator type for a list of Entry elements. The name is written as the container name, followed by the conventional name.

In the real world

Imagine generic code that needs to walk through a list of Entry elements without caring which container it came from. It can refer to list<Entry>::iterator, and if the container is later changed to one with a different internal design, the same spelled name still refers to that container's own iterator type. The caller does not need to know how that type is built, which is the practical payoff of the container providing the name.

Mistakes When Reasoning About Iterators

  • Common mistake

    Assuming every iterator is a pointer

    Why it fails

    A pointer is a reasonable choice for a vector, but a list iterator cannot simply be a pointer to an element because list elements do not know where the next element is.

    Do this instead

    Ask what information the iterator needs to move from one element to the next for the specific container it serves.

  • Common mistake

    Concluding that different iterator types have different operations

    Why it fails

    Despite different types, all iterators share their semantics and operation names, including ++ and the dereference operator.

    Do this instead

    Expect ++ and the dereference operator to behave the same way across iterators, even though their internals differ.

  • Common mistake

    Writing the specific iterator type from memory

    Why it fails

    The source notes that users rarely need to know the specific type of an iterator, because each container exposes its iterator types under the conventional names.

    Do this instead

    Refer to the container's conventional name, such as list<Entry>::iterator, instead of the concrete internal type.

  • Common mistake

    Believing a vector iterator with an index is the only valid design, when a plain pointer is also valid

Practice: Reasoning About a New Container

MEDIUM

Suppose a new container stores its values in a chain of linked pieces, much like a list. Without writing any code, describe what its iterator probably needs to hold, and explain which shared operation would move the iterator from one value to the next.

Hints
  • Recall why a pointer to a bare element is not enough for a list.
  • Think about which piece of the list the iterator should refer to so that it can reach the onward link.
  • The shared increment operator is the one that yields an iterator for the next element.

Key Takeaways

  • Iterator types differ because each iterator must hold the information it needs to do its job for one particular container type.
  • A vector iterator can be an ordinary pointer to an element, or a pointer to the vector plus an index that enables range checking.
  • A list iterator is more involved because list elements do not know where the next element is, so it commonly holds a pointer to a link that leads onward.
  • All iterators share their semantics and operation names, including ++ to reach the next element and the dereference operator to yield the element.
  • Containers expose their iterator types under the conventional names iterator and const_iterator, so code can write list<Entry>::iterator without knowing the concrete type.

Related concepts

More concepts starting with I