C++ Reference Material
STL Iterators and Iterator Adaptors
An STL iterator may be thought of as a generalized array pointer, which usually (but not always) points to a container component and is used to provide access to the value in that component for various purposes. This page contains a discussion of what is meant by an STL "range", and five tables:
One of the first ideas a programmer needs to grasp when dealing with the STL is the idea of an STL range, as given by a pair of iterators.
Probably the best analogy for an STL range is the notion of a half-open interval of integer values in mathematics, for which the notation is [a,b), where the relationship of a to b is understood to be a < b. This notation means the collection of all values from a to b, including a but not including b. Similar notation may have any of the four possible combinations of round and square brackets, and the meaning is that the value adjacent to a square bracket is in the set, but the value adjacent to a round bracket is not in the set. In all cases, all values strictly between the two values a and b are in the set.
In the context of the STL we use a similar notation to mean a similar thing. For example, we might use [iterBegin,iterEnd) to refer to the collection of all iterator values from iterBegin to iterEnd, including iterBegin but not including iterEnd. This is a rocky shoal upon which many an STL programmer has foundered (particularly beginners).
Any given iterator is a class object, and there are (conceptually) five types of iterators, as shown in the table below. These iterators are listed in order from "most powerful" (random access iterators) to "least powerful" (output iterators).
Iterator Type | Behavioral Description | Operations Supported |
---|---|---|
random access
(most powerful) |
Store and retrieve values
Move forward and backward Access values randomly |
* = ++ –> == != ––
+ – [] < > <= >= += –= |
bidirectional | Store and retrieve values
Move forward and backward |
* = ++ –> == != –– |
forward | Store and retrieve values
Move forward only |
* = ++ –> == != |
input | Retrieve but not store values
Move forward only |
* = ++ –> == != |
output
(least powerful) |
Store but not retrieve values
Move forward only |
* = ++ |
Some notes on the above table:
The table below shows, first of all, that the container adaptors
have no iterators. Each of the other classes (the three
sequential containers and the four associative containers) has a
default iterator of the type shown. Any such iterator is obtained by
declaring an object in a manner analogous to the declaration
vector<int>::iterator iter;
which supplies an iterator iter capable of pointing at the
elements in a vector container of values of type int. Each of
the seven container classes that have iterators has a typedef name
called iterator which is an alias for the class (i.e., the
type) of iterator that "goes with" that particular container class of
values. There is more to the story, of course, but that gives the
general idea.
Container Class | Iterator Type | Container Category |
---|---|---|
vector | random access | sequential |
deque | random access | |
list | bidirectional | |
set | bidirectional | associative |
multiset | bidirectional | |
map | bidirectional | |
multimap | bidirectional | |
stack | none | adaptor |
queue | none | |
priority_queue | none |
Sometimes a class will have the functionality you seek but not the right interface for accessing that functionality. For example, the STL copy() algorithm requires a pair of input iterators as its first two parameters to give the range of values to be copied. An istream object can act as a source of such data values but it does not have any iterators that the copy algorithm can use.
Similarly the third parameter of the copy() algorithm is an output iterator that directs the copied values to their proper destination. That destination could be an output stream but output streams do not directly provide any output iterators.
An adaptor class is one that acts like a "translator" by "adapting" the messages you want to send to produce messages that the other class object wants to receive.
There is an iterator adaptor class called istream_iterator that provides the interface that the copy() algorithm expects for input and translates requests from this algorithm into appropriate istream operations. And there is another one called ostream_iterator that provides the interface that the copy() algorithm expects for output and translates requests from the algorithm into appropriate ostream operations.
Stream | Iterator Adaptor |
---|---|
istream | istream_iterator
istreambuf_iterator |
ostream | ostream_iterator
ostreambuf_iterator |
Inserters (also called "insert iterators") are "iterator adaptors" that permit algorithms (the copy algorithm, for example) to operate in insert mode rather than overwrite mode, which is the default. Thus they solve the problem that crops up when an algorithm tries to write elements to a destination container not already big enough to hold them, by making the destination grow as needed. There are three kinds of inserters, as shown in the table below:
back_inserter(container_supporting_push_back)
Used to permit an algorithm to operate in "insert mode" at the "back" of a container that supports the push_back() member function. |
front_inserter(container_supporting_push_front)
Used to permit an algorithm to operate in "insert mode" at the "front" of a container that supports the push_front() member function. |
inserter(container_supporting_insert, insert_start_location)
Used to permit an algorithm to operate in "insert mode" at any "interior" point of a container that supports the insert() member function. |
Among other things, the functions shown in the table below help us to overcome the difficulties caused by the fact that
advance(inIter, num)
Moves inIter |num| positions forward if num > 0 and backward if num < 0. |
distance(inIterBegin, inIterEnd)
Returns the number of values (or positions) in the range [inIterBegin, inIterEnd). Note, however, that the return value must be cast to an int (or unsigned int), since its type is actually more complicated. |