使用迭代器遍历数组索引

13

我想知道使用迭代器相对于数组索引的主要优点是什么。我已经谷歌过了,但没有找到正确的答案。

9个回答

17

我想你是在谈论使用向量时,对吧?

主要优点是迭代器代码适用于所有STL容器,而数组索引运算符[]仅适用于向量和双端队列。这意味着您可以自由更改底层容器(如果需要),而无需重新编写每个循环。这也意味着您可以将迭代代码放入模板中,它将适用于任何容器,而不仅仅是双端队列和向量(当然还有数组)。


此外,您可以编写自定义迭代器,从数据库加载数据或使用某些算法生成数据。它非常灵活。不过,迭代器的权衡是,它们可以隐藏任意复杂的操作(例如通过网络访问数据库),这可能会导致代码执行缓慢以及异常安全性问题的混淆。 - Björn Pollex
2
Operator[] 也可以隐藏任意复杂的操作。 - Ryan
[] 也可以应用于映射/无序映射。 ;) - kennytm
@prithviraj:嗯,数组实际上没有迭代器,所以你不能这样做。有些人会说这就是为什么你应该始终使用向量的原因之一。然而,在某些情况下,您可能需要直接访问[](或at)提供的内容。 - T.E.D.
2
@prithviraj:当你设计一个库时,迭代器的重要性更加突出。只要用户提供迭代器,你就不必担心他如何表示数据。使用operator[]会让用户的操作变得更加困难。你应该阅读STL-Concepts以了解其中的区别。 - Björn Pollex
显示剩余4条评论

6

所有标准容器都提供了迭代器概念。迭代器知道如何在容器中查找下一个元素,特别是在底层结构不像数组时。并非每个容器都提供类似于数组的 operator[],因此养成使用迭代器的习惯将使代码看起来更加一致,无论你选择哪种容器。


3

您可以将集合实现抽象化。


3

对之前的回答进行进一步扩展:

  1. 使用operator[]编写循环会限制您使用支持[]并使用相同索引/大小类型的容器。否则,您需要重写每个循环以更改容器。

  2. 即使您的容器支持[],它也可能不是顺序遍历的最佳选择。[]基本上是一个随机访问运算符,对于向量而言是O(1),但根据底层容器的不同,可能会达到O(n)。

  3. 这只是一个小问题,但如果您使用迭代器,您的循环可以更轻松地转换为使用标准算法,例如std::for_each。


2

有许多数据结构,例如哈希表和链表不能被自然或快速地索引,但它们确实是可遍历的。迭代器充当一个接口,让您在不知道源代码实际实现的情况下遍历任何数据结构。


2
STL包含操作容器的算法,如transformfor_each。它们不接受索引,而是使用迭代器。迭代器有助于隐藏容器实现,使程序员更专注于算法。 for_each函数可应用于支持前向迭代器的任何内容。

1
除了其他答案中提到的点,迭代器也可以更快(特别是与operator[]相比),因为它们本质上是通过指针进行迭代。如果你做这样的事情:
for (int i = 0; i < 10; ++i)
{
    my_vector[i].DoSomething();
}

循环的每次迭代都不必要地计算my_vector.begin() + i。如果使用迭代器,增加迭代器意味着它已经指向下一个元素,因此您不需要进行额外的计算。这是一件小事,但在紧密的循环中可能会产生差异。


不,一个简单的 + 很少会花费很多周期。 - kennytm
我所做的所有测试表明,在向量中,迭代器和op[]之间的速度没有真正的差异。如果有什么区别,那么op[]会稍微快一些。 - anon
@Neil:我也测试过了,得出结论迭代器稍微快一点。不过你说的没错,“没有真正的区别”。我相信这取决于具体实现。你可能在一个迭代器没有最优实现的地方进行了测试... - user123456
2
@STingRaySC,我想象不到您使用的实现中operator[]没有被最优化地实现吗? - anon
@Neil:我真的开始喜欢你那种过度防御、自负、伪幽默的感觉了。开玩笑的,我想这是可能的(这就是我使用“可能”的原因)。 - user123456
除了向量以外的东西怎么样?对于双端队列来说,迭代器可能比 operator[] 更高效。 - Mark Ransom

1

另一个微小的区别是,您不能按索引在向量中使用erase()删除元素,必须具有迭代器。这并不是什么大问题,因为您始终可以将“vect.begin() + index”作为迭代器,但还有其他考虑因素。例如,如果您这样做,则必须始终将索引与size()进行比较,而不是某个变量分配了该值。

所有这些都不值得太多担心,但如果可以选择,我更喜欢迭代器访问,原因已经说明了这一点。


1

我认为这更多是一致性和代码重用的问题。

  • 一致性,因为您将使用所有其他具有迭代器的容器
  • 代码重用,因为编写为迭代器编写的算法不能与下标运算符一起使用,反之亦然...而STL有很多算法,因此您肯定希望在其上构建。

最后,我想说即使C数组也有迭代器。

const Foo* someArray = //...
const Foo* otherArray = new Foo[someArrayLength];

std::copy(someArray, someArray + someArrayLength, otherArray);

iterator_traits 类已经被特化,以便于指针或模型RandomAccessIterator


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