Containers and Their Elements
Two valid vector iterator designs exist. A bare pointer carries only the location of an element. A pointer to the vector plus an index carries enough information to check whether a position is inside the vector.
Visiting Elements One at a Time
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. Every time it moves on, it needs to know which element comes next. The thing that does this job is called an iterator, and this article asks a deceptively simple question about it: if two collections hold their elements in different ways, does the visitor need the same information to walk each of them?
The answer is no, and that answer explains why iterators come in different types at all. A collection stored in a contiguous run of slots and a collection stored as a chain of linked pieces both hold values in order, but the visitor's job is different in each case. Working through that difference is the best way into the topic.
Tracking Position Across Two Layouts
Picture the two containers side by side. A vector keeps its elements in a contiguous run of slots, so each element sits in order and can be reached by its position. A list keeps its elements as a chain of linked pieces. In the list, each element is a value in its own place, and the connection to the next element lives in the link that joins them. The diagram below sets the two layouts next to each other and marks the spot where an iterator is standing in each one.
Notice what the diagram does not show: the vector iterator needs nothing beyond its own position in the run of slots, while the list iterator is tied to a link. Before going further, decide for yourself which of these two starting positions would let an iterator step forward without any extra help.
Building a Vector Iterator
A vector is a container whose elements sit in order and can be reached by position. That makes the vector iterator the simplest case. It has a plain option available to it: the iterator can be an ordinary pointer to an element. A pointer is a quite reasonable way of referring to an element of a vector, so no extra machinery is needed. Holding a pointer is enough to know where you are, and it is enough to step forward to the neighboring element.
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.
Two valid vector iterator designs exist. A bare pointer carries only the location of an element. A pointer to the vector plus an index carries enough information to check whether a position is inside the vector.
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. The vector iterator could get away with a bare pointer because the vector's elements are reachable by position. The list iterator cannot.
The list iterator therefore must 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.
The comparison shows the practical difference. The vector iterator can advance from the information it already holds. The list iterator must go through the link it refers to in order to reach both the element and the onward link. That extra step is the reason its design is more involved.
Walking Three Elements Step by Step
Advancing an iterator through three elements
A vector and a list each hold three elements, and an iterator starts at the first one. Trace what each iterator must know to move to the second element and then to the third.
- 1Start the vector iterator
A bare pointer to the first element is enough. It identifies where the iterator is standing.
- 2Advance the vector iterator
Moving to the neighboring element needs no extra information. The vector's elements sit in order and can be reached by position, so the iterator steps forward from where it is.
- 3Start the list iterator
A bare pointer to the first element is not enough, because the element does not reliably know where the next element is. The iterator instead refers to a link in the chain.
- 4Advance the list iterator
The iterator follows the link it refers to, which gives access to the next element and to the link that leads onward. Those two pieces of information are what the list version must carry.
- 5Compare the two designs
Both iterators reach the second and third elements, but the list iterator must hold more information to do it. That difference is why the two iterator types differ.
The vector iterator can be as simple as a pointer, while the list iterator must refer to a link. Both reach the same logical sequence of elements, but their internal needs differ.
What 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, even when their internal representations differ. 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.
This is why a single 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.
Despite different types, all iterators share their semantics and operation names, including ++ and the dereference operator. The shared behavior is the interface; the internal design is the part that varies.
Think of two different keys that open two different doors. The keys have different shapes, but a person who knows how to turn a key does not need to know the lock's internal mechanism to open the door. Iterators work the same way: the operations ++ and dereference are the turning motion, and the internal design of each iterator type is the shape of its key.
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.
For example, list<Entry>::iterator is the general iterator type for a list of Entry elements. Writing the container name followed by the conventional name lets you refer to the right iterator type for that container. The source adds that you rarely have to worry about how that type is defined, which is the practical payoff of the container providing the name. The vector<Entry>::iterator line in the diagram follows the same pattern for a vector and is a generated parallel to the source's list example.
Mistakes About Iterator Types
Common mistake Assuming every iterator must be a plain pointer
What it looks likeTreating a list iterator as if it were just a pointer to an element.
Why it failsA list element does not reliably know where the next element is, so a bare pointer cannot step from one list element to the next.
Do this insteadA list iterator must be more involved, for example a pointer to a link, which gives access to both the element and the onward link.
Common mistake Concluding that different iterator types mean different operations
What it looks likeBelieving that a vector iterator and a list iterator each need their own set of ++ and dereference rules.
Why it failsAll iterators share their semantics and operation names, including ++ and the dereference operator.
Do this insteadLearn the shared operations once. The internal representation varies, but the behavior seen from outside stays consistent.
Common mistake Thinking a bare pointer is the only valid vector iterator
What it looks likeDismissing a pointer-plus-index design as incorrect for a vector.
Why it failsBoth designs are valid for a vector, but they carry different information.
Do this insteadChoose the design that fits the job. The pointer-plus-index design is the one that allows range checking.
Common mistake Believing you must know a container's iterator implementation before you can use it
Common mistake Writing a type name that depends on the internal design
Why it failsUsers rarely need the specific iterator type, and the container exposes its iterator types under conventional names.
Do this insteadRefer to the container's iterator through its conventional name, such as list<Entry>::iterator, rather than reconstructing the type from its details.
Trace the Iterator Design
A container holds its elements in a chain of linked pieces, and an iterator must step from one element to the next. Explain in two or three sentences what the iterator should refer to, and why a bare pointer to an element would not be enough.
Hints
- Think about whether the element itself reliably knows where the next element is.
- The source names one natural choice: a pointer to a link rather than to the bare element.
- Consider what the link gives access to: the element and the link that leads onward.
Two iterators, one for a vector and one for a list, both support ++ and the dereference operator. Name one operation that you can rely on for both, and say what the internal representation of each might look like.
Hints
- The shared operations are the increment operator ++ and the dereference operator.
- The vector iterator might be a pointer or a pointer plus an index; the list iterator might be a pointer to a link.
Key Takeaways
- 1An iterator must hold whatever information it needs to do its job for one particular kind of container, so iterator types differ as containers differ.
- 2A vector iterator can be a plain pointer, or a pointer to the vector plus an index that allows range checking.
- 3A list iterator must be more complicated than a pointer to an element, because list elements do not know where the next element is; a pointer to a link is one option.
- 4All iterators share their semantics and operation names, including ++ and the dereference operator.
- 5Each container makes its iterator types available under the conventional names iterator and
const_iterator, so users rarely need the specific type.
At a glance
- An iterator holds the information it needs for one particular container, so iterator types differ as the containers and their needs differ.
- A vector iterator can be a plain pointer, or a pointer to the vector plus an index that allows range checking.
- A list iterator is more involved than a pointer to an element, since list elements do not know where the next element is; a pointer to a link is one option.
- All iterators share their semantics and operation names, including ++ and the dereference operator.
- Containers expose their iterator types under the conventional names iterator and
const_iterator, so the names stay the same even when the types do not.