Input and output iterators

As the name suggests, an input iterator will only move forward and will have read access, and an output iterator will only move forward but will have write access. These iterators do not have random access and they do not allow backward movement. For example, an output stream may be used with an output iterator: you assign the dereferenced iterator with a data item in order to write that data item to the stream. Similarly, an input stream could have an input iterator and you dereference the iterator to get access to the next item in the stream. This behavior means that for an output iterator the only valid use of the dereference operator (*) is on the left-hand side of an assignment. It makes no sense to check the value of an iterator with !=, and you cannot check if assigning a value through the output iterator is successful.

For example, the transform function takes three iterators and a function. The first two iterators are input iterators and indicate a range of items to be transformed by the function. The result will be put in a range of items (the same size as the range of the input iterator), the first of which is indicated by the third iterator, which is an output iterator. One way to do this is as follows:

    vector<int> data { 1,2,3,4,5 }; 
vector<int> results;
results.resize(data.size());
transform(
data.begin(), data.end(),
results.begin(),
[](int x){ return x*x; } );

Here the begin and end methods return iterators on the data container that are safe to be used as input iterators. The begin method on the results container can only be used as an output iterator as long as the container has enough allocated items, and this is the case in this code because they have been allocated with resize. The function will then transform each input item by passing it to the lambda function given in the last parameter (which simply returns the square of the value). It is important to reassess what is happening here; the third parameter of the transform function is an output iterator, which means that you should expect the function to write values through this iterator.

This code works, but it requires the extra step to allocate the space, and you have the extra allocations of default objects in the container just so that you can overwrite them. It is also important to mention that the output iterator does not have to be to another container. It can be to the same container as long as it refers to a range that can be written to:

    vector<int> vec{ 1,2,3,4,5 }; 
vec.resize(vec.size() * 2);
transform(vec.begin(), vec.begin() + 5,
vec.begin() + 5, [](int i) { return i*i; });

The vec container is resized so that there is space for the results. The range of values to transform are from the beginning item to the fifth item (vec.begin() + 5 is the next item), and the place to write the transformed value is the sixth to tenth items. If you print out the vector you will get {1,2,3,4,5,1,4,9,16,25}.

Another type of output iterator is the inserter. The back_inserter is used on containers with push_back, and front_inserter is used on containers with push_front. As the name suggests, an inserter calls the insert method on the container. For example, you can use a back_inserter like this:

    vector<int> data { 1,2,3,4,5 }; 
vector<int> results;
transform(
data.begin(), data.end(),
back_inserter(results),
[](int x){ return x*x; } ); // 1,4,9,16,25

The results of the transformation are inserted into the results container with the temporary object created from the back_inserter class. Using a back_inserter object ensures that when the transform function writes through the iterator the item is inserted into the wrapped container using push_back. Note that the results container should be different to the source container.

If you want the values in reverse order, then if the container supports push_front (for example, deque), then you can use a front_inserter. The vector class does not have a push_front method, but it does have reverse iterators, so you can use them instead:

    vector<int> data { 1,2,3,4,5 }; 
vector<int> results;
transform(
data.rbegin(), data.rend(),
back_inserter(results),
[](int x){ return x*x; } ); // 25,16,9,4,1

All you need to do to reverse the order of the results is to change begin to rbegin and end to rend.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset