\cleardoublepage \chapter{Iterators} \label{chapterIterators} Iterators are a generalization of pointers that allow a programmer to work with different data structures (containers) in a uniform manner. An iterator is the glue that allows to write a single implementation of an algorithm that will work for data contained in an array, a list or some other container -- even a container that did not yet exist when the algorithm was implemented. An iterator is a concept, not a programming language construct. It can be seen as a set of requirements. A type is an iterator if it satisfies those requirements. So, for instance, a pointer to an element of an array is an iterator. We will check this later. Depending on the operations defined for an iterator, there are five categories: {\em input, output, forward, bidirectional} and {\em random access iterators}. We first have to introduce some terminology. {\bf Mutable versus constant:} There is an additional attribute that forward, bidirectional and random access iterators might have, that is, they can be {\em mutable} or {\em constant} depending on whether the result of the \ccTexHtml{{\tt operator }\raisebox{-1mm}{*}}{operator *} behaves as a reference or as a reference to a constant. {\bf Past-the-end value:} Just as a regular pointer to an array guarantees that there is a pointer value pointing past the last element of the array, so for any iterator type there is an iterator value that points past the last element of a corresponding container. These values are called {\em past-the-end} values. Values of the iterator for which the \ccTexHtml{{\tt operator }\raisebox{-1mm}{*}}{operator *} is defined are called {\em dereferenceable}. The library never assumes that past-the-end values are dereferenceable. {\bf Reachability} An iterator $j$ is called {\em reachable} from an iterator $i$ if and only if there is a finite sequence of applications of \ccStyle{operator}$\!+\!+$ to $i$ that makes $i == j$. If $i$ and $j$ refer to the same container, then either $j$ is reachable from $i$, or $i$ is reachable from $j$, or both ($i == j$). {\bf Range:} Most of the library's algorithmic templates that operate on data structures have interfaces that use {\em ranges}. A range is a pair of iterators that designate the beginning and end of the computation. A range $\left[i, i\right)$ is an {\em empty range}; in general, a range $\left[i, j\right)$ refers to the elements in the data structure starting with the one pointed to by $i$ and up to but not including the one pointed to by $j$. Range $\left[i, j\right)$ is valid if and only if $j$ is reachable from $i$. The result of the application of the algorithms in the library to invalid ranges is undefined. \medskip As we mentioned in the introduction we are a little bit sloppy in the presentation of \stl, in order to make it easier to understand. A class is said to be an iterator if it fulfills a set of requirements. In the following sections we do not present the requirements, but we state properties that are true, if the requirements are fulfilled. The difference is best seen by an example: we write that the return value of the test for equality returns a \ccStyle{bool}, but the requirement is only that the return value is convertible to \ccStyle{bool}. \newpage \begin{ccClass}{forward_iterator} \ccSection{Forward Iterator} \ccDefinition A class \ccClassName\ that satisfies the requirements of a forward iterator for the value type \ccStyle{T}, supports the following operations. \ccCreation \ccCreationVariable{it} \ccConstructor{iterator();} {} \ccConstructor{iterator(const iterator& it1);} {} \ccOperations \ccMethod{iterator& operator=(const iterator &it1);} {Assignment.} \ccMethod{bool operator==(const iterator &it1) const;} {Test for equality: Two iterators are equal if they refer to the same item.} \ccMethod{bool operator!=(const iterator &it1) const;} {Test for inequality. The result is the same as \ccStyle{!(it == it1)}.} \ccMethod{T& operator*();} {Returns the value of the iterator. If \ccClassName\ is mutable \ccStyle{*it = t} is valid. \ccPrecond \ccVar\ is dereferenceable.} \ccMethod{iterator& operator++();} {Prefix increment operation. \ccPrecond \ccVar\ is dereferenceable.} \ccMethod{const iterator& operator++(int);} {Postfix increment operation. The result is the same as that of \ccStyle{iterator tmp = it; ++it; return tmp;}. \ccPrecond \ccVar\ is dereferenceable.} \end{ccClass} \begin{ccClass}{bidirectional_iterator} \ccSection{Bidirectional Iterator} \ccDefinition A class \ccClassName\ that satisfies the requirements of a bidirectional iterator for the value type \ccStyle{T}, supports the following operations in addition to the operations supported by a forward iterator. \ccCreationVariable{it} \ccOperations \ccMethod{iterator& operator--();} {Prefix decrement operation. \ccPrecond \ccVar\ is dereferenceable.} \ccMethod{const iterator& operator--(int);} {Postfix decrement operation. The result is the same as that of \ccStyle{iterator tmp = it; --it; return tmp;}. \ccPrecond \ccVar\ is dereferenceable.} \end{ccClass} \newpage \begin{ccClass}{random_access_iterator} \ccSection{Random Access Iterator} \ccDefinition A class \ccClassName\ that satisfies the requirements of a random access iterator for the value type \ccStyle{T}, supports the following operations in addition to the operations supported by a bidirectional iterator. \ccCreationVariable{it} \vfill \ccOperations \ccMethod{iterator& operator+=(int n);} {The result is the same as if the prefix increment operation was applied $n$ times, but it is computed in constant time.} \ccMethod{iterator operator+(int n);} {Same as above, but returns a new iterator.} \ccFunction{iterator operator+(int n, iterator it);} {Same as above.} \ccMethod{iterator& operator-=(int n);} {The result is the same as if the prefix decrement operation was applied $n$ times, but it is computed in constant time.} \ccMethod{iterator operator-(int n);} {Same as above, but returns a new iterator.} \ccMethod{int operator-(const iterator &it1);} {The result \ccStyle{n} is such that \ccStyle{it1 + n ==} \ccVar. \ccPrecond \ccVar\ is reachable from \ccStyle{it1}.} \ccMethod{T& operator[](int n);} {Returns \ccStyle{*(it + n)}. \ccPrecond \ccStyle{*(it + n)} is dereferenceable} \ccMethod{bool operator<(iterator it1);} {$<$ is a total ordering relation.} \ccMethod{bool operator>(iterator it1);} {$>$ is a total ordering relation opposite to \ccStyle{<}.} \ccMethod{bool operator<=(iterator it1);} {Result is the same as \ccStyle{! it > it1}.} \ccMethod{bool operator>=(iterator it1);} {Result is the same as \ccStyle{! it < it1}.} \vfill \ccExample We promised to show why a pointer (in this case \ccStyle{V*}) is a random access iterator. In order to show that it supports the required operations, we give a program that uses them. Not all operations are used --- so it is not a complete proof --- but hopefully enough to convince the reader. Notice that the program is nothing special. It was valid \CC\ (with minor changes even valid C), long before the iterator concept was invented! The comments point to the requirements. \newpage \begin{cprog} const int N = 10; struct V { float val; }; float fill_and_add(V *b, V *e) { V *c; /* creation, first way (ForwardIterator) */ float sum; for (int i=0; i float fill_and_add(RandomAccessIterator b, RandomAccessIterator e) { RandomAccessIterator c; float sum; for (int i=0; i it(cin), end(); double sum = 0.0; while(it != end){ sum += *it; ++it; } cout << sum << endl; } \end{cprog} \end{ccClass} \begin{ccClass}{output_iterator} \ccSection{Output Iterator} \ccDefinition A class \ccClassName\ that satisfies the requirements of an output iterator for the value type \ccStyle{T}, supports the following operations. Algorithms on input iterators should never attempt to pass through the same iterator twice. They should be single pass algorithms. \ccCreation \ccCreationVariable{it} \ccConstructor{iterator();} {} \ccConstructor{iterator(const iterator& it1);} {} \ccOperations \ccMethod{iterator& operator=(const iterator &it1);} {Assignment.} \ccMethod{bool operator==(const iterator &it1) const;} {Test for equality: Two iterators are equal if they refer to the same item.} \ccMethod{bool operator!=(const iterator &it1) const;} {Test for inequality. The result is the same as \ccStyle{!(it == it1)}.} \ccMethod{T& operator*();} {Returns a reference to the value of the iterator. This operator can only be used in order to assign a value to this reference.} \ccMethod{iterator& operator++();} {Prefix increment operation. \ccPrecond \ccVar\ is dereferenceable.} \ccMethod{void operator++(int);} {Postfix increment operation. The result is the same as that of \ccStyle{iterator tmp = it; ++it; return tmp;}. \ccPrecond \ccVar\ is dereferenceable.} \ccExample The following code fragment reads numbers of the type \ccc{double} from \ccc{cin} and computes their sum. The {\sc Stl} provides an \ccc{ostream_iterator} that fulfills the output iterator requirements. As the iterator is a kind of file pointer it should be clear why only single pass algorithms can be applied on this iterator. \begin{cprog} { ostream_iterator it(cout); for(int r = 0; r < 10; r++){ *it = 3.1415 * r * r; ++it; } } \end{cprog} The above code fragment is equivalent to: \begin{cprog} { for(int r = 0; r < 10; r++){ cout << 3.1415 * r * r; } } \end{cprog} The use of output iterators is better illustrated with a function that can write into arbitrary containers: \begin{cprog} template < class OutputIterator > void generator(OutputIterator it) { for(int r = 0; r < 10; r++){ *it = 3.1415 * r * r; ++it; } } \end{cprog} and here comes its usage. \begin{cprog} { ostream_iterator it(cout); generator(it); double R[10]; generator(R); } \end{cprog} Note that the memory where the function \ccc{generator} writes to must be allocated. If you want to insert the generated doubles at the end of a list you have to use a \ccc{back_insert_iterator}. To explain this is out of the scope of this introduction to the {\sc Stl}. Please refer to the {\sc Stl} reference manuals. \end{ccClass}