Using const_iterator for Read-Only Traversal
An iterator is defined by what its operations mean, not by its underlying type. If an object honors the shared operation names and their shared meanings, it is an iterator.
Pointing at One Record at a Time
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 one, and read the record you are pointing at. The language provides a tool for exactly this job, called an iterator. Once you start using iterators, a natural first question is which specific iterator type you should write down. For most day-to-day work, the answer is that you do not need to memorize it. What you need to understand is how iterators behave, and where to find the name when you do need it.
What do you think happens?
An iterator starts out referring to Ada in a list of three names: Ada, Grace, Alan. You apply the increment operator once, then the dereference operator. What value do you get back?
Reveal answer
Grace
Applying the increment operator moves the iterator so that it refers to the next element, Grace. Applying the dereference operator then yields the element the iterator currently refers to, which is Grace. Dereferencing does not move the iterator; only increment does.
An Iterator Is a Role, Not a Type
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 operation names are consistent 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 definition of an iterator is about semantics and naming rather than about one fixed type. Any object that obeys the rules is an iterator. The practical payoff is that code written against the shared operations works with every object that plays the role, and you can reason about a loop by knowing what each operation does rather than by knowing the exact type of the thing being used.
An iterator is defined by what its operations mean, not by its underlying type. If an object honors the shared operation names and their shared meanings, it is an iterator.
Two Operations: Move Forward and Read
The two core operations pull in different directions. The increment operator changes which element the iterator points to. Applying it to an iterator yields an iterator that refers to the next element. The dereference operator does not move anything. Applying it gives you the element to which the iterator currently refers.
Keeping these two roles separate makes any loop easier to follow. Each step has two parts: one moves the pointer, and the other looks at what the pointer now refers to. If you ever lose track of a loop, ask two questions separately: where does the iterator point now, and what element does dereferencing it give me?
Where a Container Keeps Its Iterator Names
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. The container owns and advertises the type, so you look the name up through the container rather than remembering a separate name for each collection.
Walking Ada, Grace, and Alan
Imagine a list holding three names in order: Ada, Grace, and Alan. Picture an iterator that starts out referring to Ada. Each increment moves it forward by one element, and each dereference reads the element it currently refers to. The trace below follows the iterator through the list.
Tracing the iterator through three names
A list holds Ada, Grace, and Alan in that order. The iterator starts at Ada. Apply increment, dereference, increment, and dereference in sequence. What does each dereference yield?
- 1Start
The iterator refers to Ada, the first element.
- 2Increment
The increment operator yields an iterator that refers to the next element, which is Grace.
- 3Dereference
The dereference operator yields the element the iterator currently refers to, which is Grace. The iterator itself does not move.
- 4Increment again
Another increment moves the iterator to the next element, which is Alan.
- 5Dereference again
Dereferencing now yields Alan. The name you get always matches the element the iterator currently refers to.
The two dereferences yield Grace and then Alan. Each increment advances the reference by exactly one element.
Iterator and const_iterator Side by Side
Both names belong to the same container and both are iterators, so both respond to increment and dereference in the shared way described above. The difference lies in the intent the name signals. The name iterator is the container's general iterator type. The name const_iterator signals a read-only traversal, the kind of loop where you look at each element without changing it.
| Aspect | iterator | const_iterator |
|---|---|---|
| Published by | The container, under the conventional name iterator | The container, under the conventional name const_iterator |
| Responds to increment | Yes, it moves to the next element | Yes, it moves to the next element |
| Responds to dereference | Yes, it yields the element it refers to | Yes, it yields the element it refers to |
| Intended use | General iterator type of the container | Read-only traversal of the container |
Both names share the same shared operations; the name signals the intended use.
Mistakes Beginners Make with Iterators
Common mistake Assuming you must memorize a separate iterator type for every container
Why it failsEach container publishes its own iterator types under the conventional names iterator and
const_iterator, so you can look the name up through the container.Do this insteadFind the name through the container, for example list<Entry>::iterator, instead of memorizing a new name for each collection.
Common mistake Expecting dereference to move the iterator forward
Why it failsThe dereference operator does not move anything. It only yields the element the iterator currently refers to.
Do this insteadUse increment to move to the next element, and dereference to read the element you are pointing at.
Common mistake Reading list<Entry>::iterator as a single unrelated word
Why it failsThe double colon is the scope operator. It means the name iterator is looked up inside list<Entry>.
Do this insteadRead the qualified name from left to right: the container first, then the name it publishes.
Common mistake Treating a type as valid only because it has the right name, when the real test is whether it honors the shared operations
Predicting Positions Before You Run
A list holds Ada, Grace, and Alan in that order. An iterator starts at Grace. Apply increment, then dereference, then increment, then dereference. Write down what each dereference yields before checking.
Hints
- Track only where the iterator points. Increment moves it, and dereference only reads.
- After the first increment the iterator refers to Alan, the last element.
- The second dereference yields whatever element the iterator refers to at that point.
Explain in one or two sentences why a qualified name such as list<Entry>::iterator is useful even though you rarely need to know how that iterator type is defined internally.
Hints
- Think about what the scope operator tells you to look inside.
- Consider what the name tells you about which container the iterator belongs to.
Key Takeaways from Iterator Roles
- 1An 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.
- 2Increment moves the iterator to the next element. Dereference does not move it, and yields the element it currently refers to.
- 3Each container publishes its iterator types under the conventional names iterator and
const_iterator, so you find them through the container. - 4A qualified name such as list<Entry>::iterator identifies the general iterator type of that container, and the scope operator tells you to look inside the container for it.
At a glance
- An iterator is defined by shared operation names and their meanings, not by one fixed type.
- Increment moves an iterator to the next element; dereference reads the element it currently refers to without moving.
- Containers publish iterator and
const_iteratorunder conventional names, and qualified names such as list<Entry>::iterator identify them. - Use
const_iteratoras the signal for read-only traversal, and check your language's rules for exact guarantees.