Iterators are special STL objects that represent positions of elements in various STL containers. Simplistically, they play a role similar to that of a subscript in a C++ array, permitting the programmer to access a particular element, and to traverse through the container. There are many different kinds of iterators, depending on the type of container with which they are associated. For the purposes of this discussion, only a few simple iterator capabilities will be considered.
Because an iterator object is always associated with one specific type of container object, its type depends on the type of the container. For example:
#include <list> #include <vector> using namespace std; ... list<int> nums; list<int>::iterator nums_iter; vector<double> values; vector<double>::iterator values_iter; vector<double>::const_iterator const_values_iter; |
At any given time, an iterator object is associated with only one container object. There are several basic types of iterators:
Iterator type | Capabilities |
---|---|
Forward |
Can specify the position of a single element in a container. Can move in one direction from element to element in a container. |
Bidirectional |
Same as forward iterator, but can move in two directions ("forward" and "reverse") from element to element. |
Random access |
Same as bidirectional iterator, but can also move in bigger steps (skipping multiple elements). |
Iterators may be const (e.g., "const_iterator") or non-const. Constant iterators can be used to examine container elements, but not modify them. Non-constant iterators may not be used with constant container objects. Further, some specialized STL containers do not permit the use of non-constant iterators.
Various operators can be applied to an iterator object, depending on its type:
Operator | Description | Forward | Bidirectional | Random access |
---|---|---|---|---|
== |
Returns true if two iterator values specify the same element position, false otherwise. Valid only if both iterator values are associated with the same container object. |
|||
!= |
Returns true if two iterator values do NOT specify the same element position, false if they do. Valid only if both iterator values are associated with the same container object. |
|||
* |
Returns a reference to the container element at the position specified by the
iterator. Valid only if there is an element at that position. |
|||
++ |
Increments the iterator's value, so it specifies the next position in the associated container. |
|||
-- |
Decrements the iterator's value, so it specifies the previous position in the associated container. |
|
||
+= |
Adds or subtracts an offset from the iterator's value, moving it forward or backward by a specified number of positions within the container. |
|
|
|
< |
Compares two iterator values and returns true or false, depending on whether the specified relationship is true. Valid only if both iterator values are associated with the same container. |
|
|
![]() |
Iterators have many uses. A few examples are included here.
After creating a list of integers and adding some elements, we initialize the iterator nums_iter to specify the first list position (nums.begin()). The loop runs until we reach the iterator value that represents the position "just beyond" the last list element (nums.end()). Each list element is accessed by the "*" operator, which returns a reference to the element. The increment operator (++) moves the iterator to the next position in the list.
Note that we are using the iterator to modify the list elements. If this were not the case, the iterator could have been declared as "list<int>::const_iterator nums_iter;".
#include <list> // list class library using namespace std; ... list<int> nums; list<int>::iterator nums_iter; nums.push_back (0); nums.push_back (4); nums.push_front (7); cout << endl << "List 'nums' now becomes:" << endl; for (nums_iter=nums.begin(); nums_iter != nums.end(); nums_iter++) { *nums_iter = *nums_iter + 3; // Modify each element. cout << (*nums_iter) << endl; } cout << endl; |
Very often, the elements stored in an STL container are objects of class type. In this case, we may want to invoke member functions of the object referenced by an iterator. To do so, we have to watch out for operator precedence, so that the compiler understands what we are trying to do. For example:
#include <list> // list class library #include <string> // string class library using namespace std; ... list<string> words; list<string>::iterator words_iter; ... unsigned int total_length = 0; for (words_iter=words.begin(); words_iter != words.end(); words_iter++) { total_length += (*words_iter).length(); // correct // total_length += *words_iter.length(); // incorrect !! } cout << "Total length is " << total_length << endl; |
The parentheses around "*words_iter" are required when we invoke the "length()" member function. Without them, the compiler would think that the "length()" function is a member of the iterator class, not of the string class, since the "." operator would otherwise be evaluated before the unary "*" operator.
As you might expect, the parentheses would also be required if we wish to access a data member of an object referenced by an iterator.
Some STL functions (both container member functions and algorithms) require iterator arguments. This following example illustrates iterator usage by:
#include <vector> // vector class library #include <list> // list class library #include <algorithm> // STL algorithms class library using namespace std; ... vector<string> vec1; string state1 = "Wisconsin"; string state2 = "Minnesota"; vec1.push_back (state1); vec1.push_back (state2); vec1.push_back ("Illinois"); vec1.push_back ("Michigan"); sort(vec1.begin(),vec1.end()); // Sort the vector of strings. vec1.erase(vec1.begin(),vec1.end()); ... list<int> nums; list<int>::iterator nums_iter; ... nums.erase (nums.begin(), nums.end()); // Remove all elements. ... nums_iter = find(nums.begin(), nums.end(), 3); // Search the list. if (nums_iter != nums.end()) { cout << "Number " << (*nums_iter) << " found." << endl; } ... // If we found the element, erase it from the list. if (nums_iter != nums.end()) nums.erase(nums_iter); |
Copyright 2002 by Patrick Meier
Last updated on 26.08.2002 by Patrick Meier