Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you iterate backwards through an STL list?

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?

like image 484
AlanKley Avatar asked Oct 09 '08 19:10

AlanKley


People also ask

How do you iterate backwards in a list?

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.

How do you iterate through a list backwards in C++?

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.

What is the use of iterate over container in STL?

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 (++).


2 Answers

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.

like image 172
Ferruccio Avatar answered Oct 05 '22 17:10

Ferruccio


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()!

like image 28
mmocny Avatar answered Oct 05 '22 19:10

mmocny