Concepts / Iterator Concept

Iterator Concept

An iterator is defined by its semantics and the naming of its operations, not by one fixed type. Any object that obeys the rules is an iterator.

  • Programming

Why You Rarely Need the Type Name

Suppose you are writing a loop that walks through a collection of records. You need a way to point at one record, move on to the next, and read the record you are pointing at. The language provides a tool for exactly this job, called an iterator. A natural first question is which specific iterator type you should write down.

The answer this article builds toward is that, for most day-to-day work, you do not need to know that exact type. What you need to know is how iterators behave, and where to find the type name when you do need it. Before reading on, try the question below.

What do you think happens?

A list holds Ada, Grace, and Alan, in that order. An iterator starts out referring to Ada. You apply the increment operator once, then the dereference operator. What do you get back?

  • Ada

  • Grace

  • Alan

  • The iterator itself

Reveal answer
Answer:

Grace

Increment moves the iterator forward so it refers to the next element, which is Grace. Dereference then yields the element the iterator currently refers to, which is Grace.

An Iterator Is a Role, Not a Type

Definition

An iterator is defined by its semantics and the naming of its operations, not by one fixed type. Any object that obeys the rules is an iterator.

Think of an iterator less as a particular kind of thing and more as a role that many different objects can play. What makes an object an iterator is that it responds to the same operations in the same way. The operations are named consistently across all iterators, and their meanings are shared. Whatever the underlying object looks like, if it honors these shared meanings, it counts as an iterator.

This is why the concept is easier to learn through behavior than through a list of type names. Two objects with completely different internal structure can both be iterators, as long as the same operations behave the same way on each. A caller who knows the operations can work with either one without caring what the underlying object is.

Increment Moves, Dereference Reads

The two core operations pull in different directions. The increment operator changes which element the iterator points to, moving it forward to the next one. Applying increment to an iterator yields an iterator that refers to the next element.

The dereference operator does not move anything. It reads through the iterator and gives you the element currently being referred to. Applying dereference yields the element to which the iterator refers.

Key point

Keep the two roles separate. One step moves the pointer, and the other step looks at what the pointer now refers to. Once you read a loop with that split in mind, each line becomes easier to predict.

Tracing an Iterator Through Three Names

Work through a concrete case. The list holds three names in order: Ada, Grace, and Alan. The iterator starts out referring to Ada. Each arrow in the diagram below is one application of the increment operator, and each reading is what dereference would return at that moment.

Adastart: dereference yieldsAdaGraceafter one increment:dereference yields GraceAlanafter two increments:dereference yields Alanincrementincrement
After each increment the iterator refers to a new element, and dereferencing it yields that element's name. The name you get always matches the element the iterator currently refers to.
Worked example

Reading the iterator at each step

The iterator starts at Ada. Apply increment, then dereference, then increment, then dereference. Which names does dereference return?

  1. 1
    Start

    The iterator refers to Ada. No move has happened yet, so dereference would return Ada.

  2. 2
    First increment

    Increment moves the iterator so it refers to the next element, Grace. The list itself is unchanged.

  3. 3
    First dereference

    Dereference reads the element currently referred to, so it yields Grace. Dereference does not move the iterator.

  4. 4
    Second increment

    Increment again advances the reference by one element, from Grace to Alan.

  5. 5
    Second dereference

    Dereference now yields Alan, the element the iterator currently refers to.

Result

The dereference calls return Grace, then Alan.

How a Container Advertises Its Iterator Types

If iterators are defined by shared behavior, you might expect every program to name a separate iterator type for every container it uses. The source describes a convenience instead. Each container knows the iterator types that belong to it, and it makes those types available under two conventional names: iterator and const_iterator.

list<Entry>the containeriteratorgeneral iterator typeconst_iteratorsecond conventional namemakes availablemakes available
The container owns and advertises its iterator types. A caller finds them through the container rather than remembering a separate name for each collection.

The name iterator therefore comes from the container, not from a global rule. From outside the container, you reach it by qualifying the container's name, as in list<Entry>::iterator. The same qualifying pattern is how you would reach the other conventional name.

NameProvided byHow a caller reaches itWhat the source states
iteratorThe containerQualified name such as list<Entry>::iteratorIdentifies the general iterator type of that container
const_iteratorThe containerQualified name using the same container, such as list<Entry>::const_iteratorMade available under this conventional name alongside iterator; the source does not detail its behavior here

The two conventional iterator names a container makes available

Reading list<Entry>::iterator

A qualified name such as list<Entry>::iterator identifies the general iterator type of that container. Read it from left to right. The part list<Entry> names the container, with Entry as the element type it holds. The double colon then reaches into that container to get the nested name iterator, which is the iterator type the container provides.

listcontainer template<Entry>element type the containerholds::reaches into the containeriteratornested name the containerprovidesparameterized byprovides
The container template, its element type, the scope operator, and the nested name the container provides.
In the real world

A loop over a list of Entry values declares its position with list<Entry>::iterator. Reading that declaration, you can say it is a position into a list of Entry elements, and you do not need to know how the iterator type is defined internally to use it. The source notes that you rarely need that internal detail.

Mistakes Learners Make with Iterator Names

  • Common mistake

    Believing that every container needs a separate iterator type name memorized in advance

    What it looks like

    Trying to recall a unique name for the iterator of each collection in a program

    Why it fails

    Each container knows its own iterator types and makes them available under the conventional names iterator and const_iterator

    Do this instead

    Look up the type through the container, for example list<Entry>::iterator

  • Common mistake

    Expecting the dereference operator to move the iterator forward

    What it looks like

    Assuming that reading the element with dereference also advances to the next one

    Why it fails

    Dereference does not move anything. It only reads the element currently referred to

    Do this instead

    Use increment to move, and dereference to read

  • Common mistake

    Expecting the increment operator to return the element itself

    What it looks like

    Treating the result of applying increment as the name Grace

    Why it fails

    Applying increment yields an iterator that refers to the next element, not the element's value

    Do this instead

    Apply dereference to the moved iterator to get the element

Practice Tracing a Position

EASY

A list holds Ada, Grace, and Alan in that order. An iterator starts out referring to Ada. Apply the increment operator twice, then apply the dereference operator. Which element do you get, and where does the iterator refer afterward?

Hints
  • Each increment moves the iterator forward by one element.
  • Dereference does not change the position. It only reads what the iterator currently refers to.
  • Count the increments from Ada: the first gives Grace and the second gives Alan.

Key Takeaways

  • An iterator is defined by its semantics and the naming of its operations, not by one fixed type; any object that obeys the rules is an iterator.
  • Increment moves the iterator to refer to the next element, while dereference reads and yields the element the iterator currently refers to without moving it.
  • Each container knows its own iterator types and makes them available under the conventional names iterator and const_iterator, so you look them up through the container.
  • A qualified name such as list<Entry>::iterator identifies the general iterator type of that container, and you rarely need to know how that type is defined.

More concepts starting with I