Iterators are used to access elements of a sequence, and can be used in a similar manner to pointers. For example, one might use an iterator to step through the elements of a vector.
The following code creates and uses an iterator with a vector:
vector<int> the_vector; vector<int>::iterator the_iterator; for( int i=0; i < 10; i++ ) the_vector.push_back(i); int total = 0; the_iterator = the_vector.begin(); while( the_iterator != the_vector.end() ) { total += *the_iterator; ++the_iterator; } cout << "Total=" << total << endl;
Notice that you can access the elements of the container by dereferencing the iterator.
NOTES: You should prefer pre-increment operator (++iter
) to post-increment operator (iter++
)
if you are not going to use the old value.
Post-increment is generally implemented as follows:
Iter operator++(int) { Iter tmp(*this); // store the old value in a temporary object ++*this; // call pre-increment return tmp; // return the old value }
Obviously, it's less efficient than pre-increment.
Not every kind of iterator has exactly the same abilities. Reading and writing require different abilities.
Random access is efficient and convenient for a vector
, whereas it would be expensive for a list
.
For this reason, iterators are classified into five categories according to their abilities:
Iterator Category | Description | Providers | Tag |
---|---|---|---|
Input | Read values with forward movement. These can be incremented, compared, and dereferenced. | istream | input_iterator_tag |
Output | Write values with forward movement. These can be incremented and dereferenced. | ostream, inserter | output_iterator_tag |
Forward | Read or write values with forward movement. These combine the functionality of input and output iterators with the ability to store the iterators value. | slist | forward_iterator_tag |
Bidirectional | Read and write values with forward and backward movement. These are like the forward iterators, but you can increment and decrement them. | list, map, multimap, set, multiset | bidirectional_iterator_tag |
Random-access | Read and write values with random access. These are the most powerful iterators, combining the functionality of bidirectional iterators with the ability to do pointer arithmetic and pointer comparisons. | array, deque, string, vector | random_access_iterator_tag |
Each of the STL containers is associated with a category of iterator, and each of the STL algorithms uses a certain category of iterator.
For example, vectors are associated with random-access iterators, which means that they can use algorithms that require random access. Since random-access iterators encompass all of the characteristics of the other iterators, vectors can use algorithms designed for other iterators as well.
vector<int> the_vector(10); // generate_n requires output_iterator generate_n(the_vector.begin(), 5, rand); // fill requires forward_iterator fill(the_vector.begin()+5, the_vector.end(), 100); // random_shuffle requires random_access_iterator random_shuffle(the_vector.begin(), the_vector.end()); // copy requires input_iterator copy(the_vector.begin(), the_vector.end(), ostream_iterator<int>(cout, " ")); // reverse_copy requires bidirectional_iterator reverse_copy(the_vector.begin(), the_vector.end(), ostream_iterator<int>(cout, " "));
The <iterator>
header file defines two auxiliary functions.
void advance( input_iterator& pos, Dist n );
advance()
lets pos
step n
elements forward (or backward).
For bidirectional and random_access_iterators, n
can be negative to step backward.
For random_access_iterators, advance()
runs in constant time (simply calls pos
+=n
).
For all other iterators, advance()
has linear complexity (calls ++pos
n
times).
typename iterator_traits<input_iterator>::difference_type distance( input_iterator pos1, input_iterator pos2 );
distance()
returns the distance between two iterators.
For random_access_iterators, distance()
runs in constant time (simply returns pos2
- pos1
).
For all other iterators, distance()
runs in linear time ( pos1
is incremented until it reaches pos2
, and returns the number of incrementation).
Iterators to exisiting elements in a container can become invalidated when the container is changed. This makes changing the container while iterating it problematic. The containers offer different guarantees in this regard:
Related topics: http://www.oreillynet.com/pub/a/network/2005/10/18/what-is-iterator-in-c-plus-plus.html