使用迭代器获取向量的索引

5

在迭代向量元素时,最好使用迭代器而不是索引(请参见为什么使用迭代器而不是数组索引?)。

std::vector<T> vec;
std::vector<T>::iterator it;
for ( it = vec.begin(); it != vec.end(); ++it )
{
   // do work
}

然而,在循环体中使用索引可能是必要的。在考虑性能和灵活性/可扩展性的情况下,以下哪种方法更可取?

  1. 回到索引循环
    std::vector vec;
    size_t i;
    for ( i = 0; i < vec.size(); ++i )
    {
       // 使用 i
    }
    
  2. 计算偏移量
    std::vector vec;
    std::vector::iterator it;
    for ( it = vec.begin(); it != vec.end(); ++it )
    {
       size_t i = it - vec.begin(); 
       // 使用 i
    }
    
  3. 使用 std::distance
    std::vector vec;
    std::vector::iterator it;
    for ( it = vec.begin(); it != vec.end(); ++it )
    {
       size_t i = std::distance( vec.begin(), it );
       // 使用 i
    }
    
7个回答

13

如果你计划仅使用向量,那么你可能想要切换回索引循环,因为它比迭代器循环更清晰地传达了你的意图。不过,如果你将来的程序演变可能导致容器的改变,那么你应该坚持使用迭代器,并使用std::distance,这保证适用于所有标准迭代器。


8

使用std::distance更加通用,因为它适用于所有迭代器,而不仅仅是随机访问迭代器。在随机访问迭代器的情况下,它应该与It - vec.begin()一样快。

It - vec.begin()基本上是指针运算。


6

4

回到使用索引循环。

基本上在90%的情况下,迭代器是更好的选择,而这就是那10%之一。通过使用迭代器,你会使代码变得更加复杂,因此更难理解,而一开始使用迭代器的原因就是为了简化你的代码。


忘了提及性能,通常可以假定索引循环具有更好的性能,但在这两种情况下性能非常相似。 - Guvante
我不能说我同意。循环体可能包含其他解引用迭代器的代码。迭代器并不是为了让你的代码更简单,而是让你的代码更通用。通过使用迭代器,您可以将向量替换为列表,它仍然可以工作。 - QBziZ
另外,std::map或std::set迭代器并不笨。如果我循环遍历所有可能的键,那可能需要很长时间。而且,我必须在每个键上执行一个O(log(n))的查找。因此,我的循环将需要O(m*log(n))的时间。使用迭代器,我可以在O(n)的时间内循环遍历集合。 - Doug T.

1
你缺少一种解决方案:保留索引以备需要,但不要将其用作循环条件。这也适用于列表,并且每次循环的成本为O(n)和一个额外的寄存器。

0

对于未来的开发原因,我总是倾向于坚持使用迭代器。

在上面的例子中,如果您决定将std::vector替换为std::set(也许您需要一个唯一的元素集合),使用迭代器和distance()函数仍然可以工作。

我相信任何性能问题都会被优化到可以忽略不计的程度。


0

对于向量,我总是使用整数方法。向量中的每个索引与数组查找的速度相同。如果我将要经常使用该值,则为方便起见,我会创建一个引用。

理论上,向量迭代器可能比索引略快,因为它们使用指针算术来遍历列表。然而,通常我发现可读性超过了最小运行时差异。

我使用迭代器来处理其他容器类型,有时当您不需要循环变量时也可以使用。但是,如果您需要循环变量,则除了使循环更难输入之外,什么也没有做。(我迫不及待地等待c++0x的auto..)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接