This means that incrementing the pointer is only meaningful as an iterator over arrays.
Why not just overload the ++ and * operators on the list class rather than create a whole class? Functionally, there isn't much difference. Putting the operators in the list class, kind of merges two kinds of objects. The list class encapsulates all the information we have about the list in one place. Including the iterator operations in there mushes the two concepts. Creating an iterator class encapsulates what we know about the pointers in its own class. This is a little vague. The usefulness of a separate iterator class should become clearer when we talk about iterator adaptor classes. The key feature of an iterator over a simple pointer is the ability to assign arbitrary code to the operators * and ++. Again, this will be clearer in iterator adaptors. Iterators are used heavily in the algorithms in the STL. This is because they can be defined so that all iterators implement the same methods even though they are iterating over many different types.
Iterators are like pointers, you dereference the pointer using the *
operator. You can add to the end of a vector using the push_back() method
but there is no push_front() method. Some examples are:
vector<int> v;
vector::iterator i=v.begin(); // i points to the first element
in v
i++; // move to the next element
i--; // move to the previous element
v[3]=9; // set element 3 to 9
But iterators are supposed to be incrementable and dereferencable. If cin were an iterator, you would expect to do cin++ to go to the next input element and *cin to fetch it.
When we have seen problems like this before, we have overloaded the operators to make them act they way we want to. We will do that here by building an adaptor class to make the iostream look like an iterator class. The STL contains an adaptor class called istream_iterator that overloads the increment and dereference operators so that cin++ doesn't do anything. The code probably looks like istream_iterator & operator++() {};
The * operator simply reads the next thing from the input stream. These iterator adaptors can be used on any input stream including istrstreams and ifstreams.
A common use of iterator adaptors is in some of the STL algorithms that
use iterator ranges. For example, the copy() functions moves the
objects in the range defined by the first two arguments to the third.
vector<int> v1,v2;
// some code to put stuff in v1
copy(v1.begin(),v1.end(),v2.begin());
Starting at the first element in v1, copy it to the first element in v2. Increment both pointers and do it again until we reach the end pointer on v1. One thing you have to be careful about when using the copy() function this way is that it assumes that the destination has the space needed to put the source elements in. A little later we will see a way to make this use push_back() to add elements to the destination.
Now if we could use standard output as an iterator, we could use copy()
to send the elements of an array to the output. The standard way to do
this is
for(int i=0;i < v.size; i++)
cout << v[i];
We can use an ostream_iterator to convert the standard output operator
to an iterator.
ostream_iterator<mytype,ptrdiff_t> o(cout)
is how you declare
an adaptor. The second type to the template can usually be left out. It
refers to the memory model needed for compilers that have memory models.
The template should default to ptrdiff_t. If it complains, use ptrdiff_t.
Here is an example of using copy to write out a vector. copy(v.begin(),v.end(), ostream_iterator<int>(cout,"\n"));
The second argument to the adaptor is a separator that is printed after each element.
Input can be done as well.
copy(istream_iterator<int>(cin),istream_iterator<int>(),
v.begin());
This still presents the problem of making sure there is enough space
in the vector before running this. Another kind of adaptor can be used
to fix this.
copy(istream_iterator<int>(cin),
istream_iterator<int>(),
back_insert_iterator<vector<int>>(v));
The back insert adaptor turns the dereference calls into calls to the push_back() method on vectors.
This example really shows the ability to use classes and operator overloading to do things that would be very difficult in C.