theVoid theVoid - 19 days ago 5
C++ Question

Iterate backwards using iterators

For simplification of my question i will use

std::string::iterator
and
std::string::reverse_iterator
but the question is about iterators in general.

Is there any particular reason to iterate backwards using the following loop:

std::string s = "something";
for (std::string::reverse_iterator it = s.rbegin(); it != s.rend(); ++it)


rather than this one:

std::string s = "something";
std::string::iterator it = in.end();
while(it!=in.begin())
{
it--;
//do something
}

Answer

Reverse iterators allow you to reuse generic code because you can treat them like normal iterators, calling ++ to go backwards. For example:

#include <iostream>
#include <string>

template <class Iterator>
void printAll(Iterator begin, Iterator end)
{
    for (auto it = begin; it != end; ++it) // ++ can mean "go backwards"
                                           // if Iterator is a reverse
                                           // iterator
    {
        std::cout << *it << "\n";
    }
}

int main()
{
    std::string s = "123";
    printAll(s.begin(), s.end());   // prints 1, 2, 3
    printAll(s.rbegin(), s.rend()); // prints 3, 2, 1
}

Notice how you do not need to write a reverse version for printAll using --.

Now, consider all the functions in <algorithm>. The existence of reverse iterators means that you can easily use all of them in a reverse manner. For example, there is std::copy_n, but not std::reverse_copy_n, but with reverse iterators, it's not necessary, because you can write something like this:

#include <iostream>
#include <string>
#include <algorithm>
#include <iterator>

int main()
{
    std::string input = "abcdef";
    std::string output;
    std::string output_reversed;

    // copy the first 3 elements:
    std::copy_n(input.begin(), 3, std::back_inserter(output));

    // copy the first 3 elements going backwards, starting at the last one:
    std::copy_n(input.rbegin(), 3, std::back_inserter(output_reversed));

    std::cout << output << "\n";          // prints abc
    std::cout << output_reversed << "\n"; // prints fed
}

For non-generic code, such as in your question, it's more of a style issue, with few technically sound arguments to prefer one over the other.