Professional C__ - Marc Gregoire [291]
For example, you can use the ostream_iterator with the copy() algorithm to print the elements of a container with only one line of code. The first parameter of copy() is the start iterator of the range to copy, the second parameter is the end iterator of the range, and the third parameter is the destination iterator:
vector for (int i = 0; i < 10; i++) { myVector.push_back(i); } // Print the contents of the vector. copy(myVector.begin(), myVector.end(), ostream_iterator Code snippet from IteratorAdapters\StreamIterators.cpp Similarly, you can use the input stream iterator, istream_iterator, to read values from an input stream using the iterator abstraction. Elements are read using operator>>. An istream_iterator can be used as sources in the algorithms and container methods. Its usage is less common than that of the ostream_iterator, so we don’t show an example here. Insert Iterators As Chapter 13 mentions, algorithms like copy() don’t insert elements into a container; they simply replace old elements in a range with new ones. In order to make algorithms like copy() more useful, the STL provides three insert iterator adapters that actually insert elements into a container. They are templatized on a container type, and take the actual container reference in their constructor. By supplying the necessary iterator interfaces, these adapters can be used as the destination iterators of algorithms like copy(). However, instead of replacing elements in the container, they make calls on their container to actually insert new elements. The basic insert_iterator calls insert(position, element) on the container, the back_insert_iterator calls push_back(element), and the front_insert_iterator calls push_front(element). For example, you can use the back_insert_iterator with the remove_copy_if() algorithm to populate vectorTwo with all elements from vectorOne that are not equal to 100: // The implementation of populateContainer() is identical to that shown in // Chapter 13, so it is omitted here. vector populateContainer(vectorOne); back_insert_iterator remove_copy_if(vectorOne.begin(), vectorOne.end(), inserter, [](int i){return i==100;}); copy(vectorTwo.begin(), vectorTwo.end(), ostream_iterator Code snippet from IteratorAdapters\BackInsertIterator.cpp As you can see, when you use insert iterators, you don’t need to size the destination containers ahead of time. You can also use the back_inserter() utility function to create a back_insert_iterator. For example, in the previous example, you can remove the line which defines the inserter variable and rewrite the remove_copy_if() call as follows. The result is exactly the same as the previous implementation: remove_copy_if(vectorOne.begin(), vectorOne.end(), back_inserter(vectorTwo), [](int i){return i==100;}); The insert_iterator and front_insert_iterator work similarly, except that the insert_iterator also takes an initial iterator position in its constructor, which it passes to the first call to insert(position, element). Subsequent iterator position hints are generated based on the return value from each insert() call. One huge benefit of insert_iterator is that it allows you to use associative containers as destinations of the modifying algorithms. Chapter 13 explains that the problem with associative containers is that you are not allowed to modify the elements over which you iterate. By using an insert_iterator, you can instead insert elements, allowing the container to sort them properly internally. Associative containers actually support a form of insert() that takes an iterator position, and are supposed to use the position as a “hint,” which they can ignore. When you use an insert_iterator on an associative container, you can pass the begin() or end() iterator of the container to use as the hint. Here is the previous example modified so that the destination container is a set instead of a vector: // The implementation