I have a situation where I'm marching through a vector, doing things:
std::vector<T>::iterator iter = my_list.begin();
for ( ; iter != my_list.end(); ++iter )
{
if ( iter->doStuff() ) // returns true if successful, false o/w
{
// Keep going...
}
else
{
for ( ; iter != m_list.begin(); --iter ) // ...This won't work...
{
iter->undoStuff();
}
}
}
Under normal conditions - assuming everything goes well - I march all the way to my_list.end()
and end the loop successfully.
However, if something goes wrong while I'm doing stuff, I want to be able to undo everything - basically retrace my steps back to the very beginning of the vector, undoing everything one at a time in reverse order.
My problem is that when I get to my_list.begin()
- as shown in the nested for loop - I'm really not done yet because I still need to call undoStuff()
on my first element in the list. Now, I could just make the final call outside of the loop, but this seems a little unclean.
The way I see it, I'm only done when I get to my_list.rend()
. However, I can't compare a std::vector::iterator
to a std::vector::reverse_iterator
.
Given what I'm trying to do, what's the best choice of iterator-type / loop combination?
While using reverse iterators via rbegin()
and rend()
works nicely, unfortunately I find that converting between reverse and non-reverse iterarotrs tends to be quite confusing. I can never remember without having to go through a logic-puzzle exercise whether I need to increment or decrement before or after the conversion. As a result I generally avoid the conversion.
Here's the way I'd probably code your error handling loop. Note that I'd think that you wouldn't have to call undoStuff()
for the iterator that failed - after all, doStuff()
said it didn't succeed.
// handle the situation where `doStuff() failed...
// presumably you don't need to `undoStuff()` for the iterator that failed
// if you do, I'd just add it right here before the loop:
//
// iter->undoStuff();
while (iter != m_list.begin()) {
--iter;
iter->undoStuff();
}