I'm writing some cross-platform code between Windows and Mac.
If list::end() "returns an iterator that addresses the location succeeding the last element in a list" and can be checked when traversing a list forward, what is the best way to traverse backwards?
This code workson the Mac but not on Windows (can't decrement beyond first element):
list<DVFGfxObj*>::iterator iter = m_Objs.end(); for (iter--; iter!=m_Objs.end(); iter--)// By accident discovered that the iterator is circular ? { }
this works on Windows:
list<DVFGfxObj*>::iterator iter = m_Objs.end(); do{ iter--; } while (*iter != *m_Objs.begin());
Is there another way to traverse backward that could be implemented in a for loop?
Iterate over the list using for loop and reversed() reversed() function returns an iterator to accesses the given list in the reverse order. Let's iterate over that reversed sequence using for loop i.e. It will print the wordList in reversed order.
C++ Iterators Reverse Iterators A reverse iterator is made from a bidirectional, or random access iterator which it keeps as a member which can be accessed through base() . To iterate backwards use rbegin() and rend() as the iterators for the end of the collection, and the start of the collection respectively.
Iterators play a critical role in connecting algorithm with containers along with the manipulation of data stored inside the containers. The most obvious form of an iterator is a pointer. A pointer can point to elements in an array and can iterate through them using the increment operator (++).
Use reverse_iterator
instead of iterator
. Use rbegin()
& rend()
instead of begin()
& end()
.
Another possibility, if you like using the BOOST_FOREACH
macro is to use the BOOST_REVERSE_FOREACH
macro introduced in Boost 1.36.0.
The best/easiest way to reverse iterate a list is (as already stated) to use reverse iterators rbegin/rend.
However, I did want to mention that reverse iterators are implemented storing the "current" iterator position off-by-one (at least on the GNU implementation of the standard library).
This is done to simplify the implementation, in order for the range in reverse to have the same semantics as a range forward [begin, end) and [rbegin, rend)
What this means is that dereferencing an iterator involves creating a new temporary, and then decrementing it, each and every time:
reference operator*() const { _Iterator __tmp = current; return *--__tmp; }
Thus, dereferencing a reverse_iterator is slower than an normal iterator.
However, You can instead use the regular bidirectional iterators to simulate reverse iteration yourself, avoiding this overhead:
for ( iterator current = end() ; current != begin() ; /* Do nothing */ ) { --current; // Unfortunately, you now need this here /* Do work */ cout << *current << endl; }
Testing showed this solution to be ~5 times faster for each dereference used in the body of the loop.
Note: Testing was not done with the code above, as that std::cout would have been the bottleneck.
Also Note: the 'wall clock time' difference was ~5 seconds with a std::list size of 10 million elements. So, realistically, unless the size of your data is that large, just stick to rbegin() rend()!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With