3

我有一种情况,我正在穿过一个向量,做一些事情:

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

在正常情况下 - 假设一切顺利 - 我一路前进my_list.end()并成功结束循环。

但是,如果在我做事时出现问题,我希望能够撤消所有内容——基本上将我的步骤追溯到向量的最开始,以相反的顺序一次撤消所有内容。

我的问题是,当我到达时my_list.begin()- 如嵌套 for 循环所示 - 我真的还没有完成,因为我仍然需要调用undoStuff()列表中的第一个元素。现在,我可以在循环之外进行最终调用,但这似乎有点不干净。

在我看来,我只有在到达时才完成my_list.rend()。但是,我无法将 astd::vector::iterator与 a进行比较std::vector::reverse_iterator

鉴于我正在尝试做的事情,迭代器类型/循环组合的最佳选择是什么?

4

9 回答 9

8

当谈到 STL 向量时,我有点生疏,但是可以std::vector::reverse_iterator从您的初始迭代器创建一个吗?然后,您只需要从您在前进时所处的最后一个项目开始,并且能够将其与my_list.rend()以确保第一个项目得到处理。

于 2009-03-11T00:20:09.430 回答
4

operator[]()如果向量可以使您的代码更清晰、更简单和/或更高效,那么当然没有理由不使用向量。

于 2009-03-11T00:24:52.710 回答
4

虽然通过rbegin()and使用反向迭代器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();
}
于 2009-03-11T03:26:27.267 回答
2

不使用 a reverse_iterator,您可以这样向后走:

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

虽然这会创建 的副本iter,但成本应该不会太大。您可以重构以获得更快的速度:

while(iter != m_list.begin())
{
    --iter;
    iter->undoStuff();
}
于 2009-03-11T00:37:48.747 回答
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);
于 2009-03-11T09:22:25.897 回答
1

您需要使用 rbegin() 来获得可逆迭代器。

个人还是比较喜欢

for (int i=0;i<vecter.size();i++) { }
于 2009-03-11T00:26:05.857 回答
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())
于 2009-03-11T00:38:49.493 回答
0

这就是我所说的工程,但它非常有趣

// 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()));
}
于 2009-03-11T03:31:09.080 回答
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();
  }
}
于 2011-09-27T04:03:52.013 回答