37

我正在编写一些 Windows 和 Mac 之间的跨平台代码。

如果 list::end() “返回一个迭代器,该迭代器指向列表中最后一个元素之后的位置”并且可以在向前遍历列表时检查,那么向后遍历的最佳方法是什么?

此代码适用于 Mac,但不适用于 Windows(不能递减超过第一个元素):

list<DVFGfxObj*>::iterator iter = m_Objs.end();
for (iter--; iter!=m_Objs.end(); iter--)// By accident discovered that the iterator is circular ?
{
}

这适用于 Windows:

list<DVFGfxObj*>::iterator iter = m_Objs.end();
    do{
        iter--;
    } while (*iter != *m_Objs.begin());

是否有另一种可以在 for 循环中实现的向后遍历方法?

4

5 回答 5

63

使用reverse_iterator而不是iterator. 使用rbegin()&rend()代替begin()& end()

如果您喜欢使用BOOST_FOREACH宏,另一种可能性是使用BOOST_REVERSE_FOREACHBoost 1.36.0 中引入的宏。

于 2008-10-09T19:58:08.233 回答
17

反向迭代列表的最佳/最简单方法是(如前所述)使用反向迭代器 rbegin/rend。

但是,我确实想提一下,反向迭代器的实现是将“当前”迭代器位置逐一存储(至少在标准库的 GNU 实现中)。

这样做是为了简化实现,以便反向范围与正向范围 [begin, end) 和 [rbegin, rend) 具有相同的语义

这意味着取消引用迭代器涉及创建一个新的临时对象,然后每次递减它:

  reference
  operator*() const
  {
_Iterator __tmp = current;
return *--__tmp;
  }

因此,取消引用 reverse_iterator 比普通迭代器慢。

但是,您可以改为使用常规双向迭代器自己模拟反向迭代,避免这种开销:

for ( iterator current = end() ; current != begin() ; /* Do nothing */ )
{
    --current; // Unfortunately, you now need this here
    /* Do work */
    cout << *current << endl;
}

测试表明,对于循环主体中使用的每个取消引用,该解决方案的速度提高了约 5 倍。

注意:上面的代码没有进行测试,因为 std::cout 会成为瓶颈。

另请注意:“挂钟时间”差异约为 5 秒,std::list 大小为 1000 万个元素。因此,实际上,除非您的数据量很大,否则请坚持使用 rbegin() rend()!

于 2008-10-21T20:33:18.520 回答
14

您可能需要反向迭代器。从记忆里:

list<DVFGfxObj*>::reverse_iterator iter = m_Objs.rbegin();
for( ; iter != m_Objs.rend(); ++iter)
{
}
于 2008-10-09T19:59:55.640 回答
6

正如 Ferruccio 已经提到的,使用 reverse_iterator:

for (std::list<int>::reverse_iterator i = s.rbegin(); i != s.rend(); ++i)
于 2008-10-09T20:05:24.240 回答
5

这应该有效:

list<DVFGfxObj*>::reverse_iterator iter = m_Objs.rbegin();
for (; iter!= m_Objs.rend(); iter++)
{
}
于 2008-10-09T20:05:42.603 回答