使用迭代器走路和解散std :: vector最干净的方法是什么?
题
我有一种情况,我正在通过矢量进行操作:
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(); } } }
在正常情况下 - 假设一切顺利 - 我一直走到 my_list.end()
并成功结束循环。
然而,如果在我做某事时出现问题,我希望能够撤消所有内容 - 基本上将我的步骤回溯到向量的开头,一次一个地以相反的顺序撤消所有内容。
我的问题是,当我到达 my_list.begin()
时 - 如嵌套for循环中所示 - 我还没有完成,因为我仍然需要调用 undoStuff( )
在我列表中的第一个元素上。现在,我可以在循环之外进行最后的调用,但这看起来有点不洁净。
我看到它的方式,我只有在到达 my_list.rend()
时才会这样做。但是,我无法将std :: vector :: iterator与std :: vector :: reverse_iterator进行比较。
鉴于我正在尝试做什么,迭代器类型/循环组合的最佳选择是什么?
解决方案
虽然通过 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();
}
其他提示
对于STL向量,我有点生疏,但是可以从初始迭代器创建 std :: vector :: reverse_iterator
吗?然后你只需要从前进的最后一个项目开始,并且能够将它与 my_list.rend()
进行比较,以确保处理第一个项目。
当然没有理由不使用向量 operator []()
,如果这样可以使您的代码更清晰,更简单和/或更高效。
这取决于 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);
不使用 reverse_iterator
,您可以这样向后走:
while(iter-- != m_list.begin())
{
iter->undoStuff();
}
虽然这会创建 iter
的副本,但成本不应太高。你可以重构以获得更好的速度:
while(iter != m_list.begin())
{
--iter;
iter->undoStuff();
}
您需要使用rbegin()来获取可逆迭代器。
我个人还是喜欢
for (int i=0;i<vecter.size();i++) { }
好的,我会在这里出去......
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())
这就是我所说的工程学,但它非常有趣
// 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()));
}
这可以通过 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();
}
}