What is the cleanest way to go and abandon std :: vector using iterators?

I have a situation where I go through a vector doing things:

std :: vector :: 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 - if everything goes well - I go through my_list.end()and successfully complete the cycle.

However, if something goes wrong when I do something, I want to be able to undo everything - basically, return my steps back to the very beginning of the vector, undoing everything one by one in the reverse order.

, my_list.begin() - - , undoStuff() . , .

, , , my_list.rend(). std::vector:: iterator std::vector:: reverse_iterator.

, , /?

+3
9

rbegin() rend() , , , . , , . .

, , . , , undoStuff() - , doStuff() , .

// 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();
}
+4

, STL, std::vector::reverse_iterator ? , , , my_list.rend(), , .

+8

, operator[](), , / .

+4

reverse_iterator :

while(iter-- != m_list.begin())
{
    iter->undoStuff();
}

iter, . :

while(iter != m_list.begin())
{
    --iter;
    iter->undoStuff();
}
+2

, doStuff(), . , , , (.. ) , , .

std::vector<Foo> workingCopy;
workingCopy.assign(myVector.begin(), myVector.end());

bool success = true;
auto iter = workingCopy.begin();
for( ; iter != workingCopy.end() && success == true; ++iter )
    success = iter->doStuff();

if( success )
    myVector.swap(workingCopy);
+2

rbegin(), .

for (int i=0;i<vecter.size();i++) { }
+1

, .

std::vector iterator iter = my_list.begin();
bool error = false;

while(iter != my_list.end())
{
  error = !iter->doStuff();
  if(error)
    break
  else
    iter++;
}

if(error)
do
{
  iter->undoStuff();
  iter--;
} 
while(iter != my_list.begin())
+1

, ,

// This also can be done with adaptators I think
// Run DoStuff until it failed or the container is empty
template <typename Iterator>
Iterator DoMuchStuff(Iterator begin, Iterator end) {
  Iterator it = begin;
  for(; it != end; ++it) {
    if(!*it->DoStuff()) {
      return it;
    }
  }
  return it;
}

// This can be replaced by adaptators
template <typename Iterator>
void UndoMuchStuff(Iterator begin, Iterator end) {
  for(Iterator it = begin; it != end; ++it) {
    it->UndoStuff();
  }
}

// Now it is so much easier to read what we really want to do
typedef std::vector<MyObject*> MyList;
typedef MyList::iterator Iterator;
typedef MyList::reverse_iterator ReverseIterator;
Iterator it = DoMuchStuff(my_list.begin(), my_list.end());
if(it != my_list.end()) {
  // we need to unprocess [begin,it], ie including it
  UndoMuchStuff(ReverseIterator(1+it), ReverseIterator(my_list.begin()));
}
0

reverse_iterator:

bool shouldUndo(false);
std::vector::iterator iter(my_list.begin()), end(my_list.end());
for ( ; iter != end && !shouldUndo; ++iter )
{
  shouldUndo = iter->doStuff();   // returns true if successful, false o/w
}
if (shouldUndo) {
  reverse_iterator<std::vector::iterator> riter(iter), rend(my_list.rend());
  //Does not call `undoStuff` on the object that failed to `doStuff`
  for ( ; riter != rend; ++riter )
  {
    iter->undoStuff();
  }
}
0

Source: https://habr.com/ru/post/1704551/


All Articles