C++ 什么';使用迭代器遍历和取消遍历std::vector最干净的方法是什么?

C++ 什么';使用迭代器遍历和取消遍历std::vector最干净的方法是什么?,c++,vector,loops,iterator,for-loop,C++,Vector,Loops,Iterator,For Loop,我有一种情况,我在向量中行进,做一些事情: 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 !=

我有一种情况,我在向量中行进,做一些事情:

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();
    }
  }
}
std::vector::iterator iter=my_list.begin();
for(;iter!=my_list.end();++iter)
{
if(iter->doStuff())//如果成功则返回true,否则返回false
{
//继续。。。
}
其他的
{
对于(;iter!=m_list.begin();--iter)/…这不起作用。。。
{
iter->undoStuff();
}
}
}
在正常情况下-假设一切顺利-我一直前进到
my_list.end()
并成功结束循环

然而,如果我在做一些事情的时候出现了问题,我希望能够撤销一切——基本上是将我的步骤回溯到向量的最开始,以相反的顺序一次撤销一切

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

在我看来,只有当我进入
my_list.rend()
时,我才能完成。但是,我无法将
std::vector::iterator
std::vector::reverse\u iterator
进行比较


考虑到我所要做的,迭代器类型/循环组合的最佳选择是什么?

对于STL向量,我有点生疏,但是否可以从初始迭代器创建一个
std::vector::reverse\u迭代器?然后,您只需要在前进时从最后一个项目开始,并能够将其与
my_list.rend()
进行比较,以确保第一个项目已被处理。

当然没有理由不使用向量
操作符[]()
,如果这使您的代码更清晰,更简单和/或更高效。

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

就我个人而言,我还是更喜欢

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

for(int i=0;i无需使用
reverse\u迭代器
,您可以通过以下方式向后走:

while(iter-- != m_list.begin())
{
    iter->undoStuff();
}
虽然这创建了一个iter的副本,但成本应该不会太高。您可以重构以提高速度:

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

好吧,我要冒险出去

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

通过
rbegin()和
rend()使用反向迭代器时
工作得很好,不幸的是,我发现反向和非反向iterarotr之间的转换往往非常混乱。如果不进行逻辑拼图练习,我永远记不起是否需要在转换之前或之后递增或递减。因此,我通常避免转换

下面是我可能编写错误处理循环的方法。请注意,我认为您不必为失败的迭代器调用
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();
}

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

// 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()));
}
//我想这也可以通过适配器来实现
//运行DoStuff,直到失败或容器为空
模板
迭代器DoMuchStuff(迭代器开始、迭代器结束){
迭代器it=begin;
for(;it!=end;++it){
如果(!*it->DoStuff()){
归还它;
}
}
归还它;
}
//这可以用适配器代替
模板
void UndoMuchStuff(迭代器开始、迭代器结束){
for(迭代器it=begin;it!=end;++it){
它->撤销东西();
}
}
//现在阅读我们真正想做的事情变得容易多了
typedef std::向量MyList;
typedef MyList::迭代器迭代器;
typedef MyList::reverse\u迭代器ReverseIterator;
迭代器it=DoMuchStuff(my_list.begin(),my_list.end());
if(it!=my_list.end()){
//我们需要取消处理[开始]
UndoMuchStuff(ReverseIterator(1+it)、ReverseIterator(my_list.begin());
}

这取决于
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);
std::矢量工作副本;
workingCopy.assign(myVector.begin(),myVector.end());
布尔成功=真;
auto iter=workingCopy.begin();
for(;iter!=workingCopy.end()&&success==true;++iter)
success=iter->doStuff();
如果(成功)
myVector.swap(工作副本);

这可以通过
反向迭代器来完成:

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();
  }
}
bool应该撤销(false);
迭代器iter(my_list.begin()),end(my_list.end());
对于(;iter!=结束和!shoulduo;++iter)
{
shouldUndo=iter->doStuff();//如果成功则返回true,否则返回false
}
如果(应该撤消){
反向迭代器riter(iter),rend(my_list.rend());
//不对未能“doStuff”的对象调用“undoStuff”`
对于(;riter!=rend;++riter)
{
iter->undoStuff();
}
}

是的,您可以这样做。请参阅此处:在大多数情况下效率不高。迭代器是STL数据类型的抽象指针。[]例如,对于(STL)链表,效果非常糟糕。我不知道std::list有一个运算符[]啊,对不起,尼尔。我不知道。要注意的是,使用迭代器在映射和集之间进行迭代也更好。保持一致性很好。@strager,不能使用运算符[]在映射或集之间进行迭代也可以。不知道你想说什么。@Brian Neal,我是说使用迭代器的迭代在几个STL容器中是一致的,而使用[]不是。也许我误读了这一点-但是如果第一个元素有错误,那么第二个循环中的iter似乎会超出范围并做坏事?我认为你是对的,至少,递减begin()迭代器可能没有定义。太糟糕了,它肯定会越过难看的界限,必须用if替换iter(iter!=my_list.begin())iter-->:)如果第一个元素出现故障,while循环将永远无法进入?@R