向量迭代器 < 或 !=

30

有人能帮我理解在涉及 for 循环中的向量迭代器时,使用 !=< 是否有很大的区别吗?

我的意思是,无论您使用 != 还是 <,结果都应该是相同的吗?

for (vector<int>::iterator i = vec.begin(); i != vec.end(); i++)
    // DO STUFF
for (vector<int>::iterator i = vec.begin(); i < vec.end(); i++)
    // DO STUFF

我知道最常见的方法是使用!=,但如果使用<,这会是一个大问题吗?


3
可能比 "!=" 慢,因为它需要检查 rhs 是否在 lhs 之后;但这在某种程度上取决于实现方式。 - UKMonkey
6
建议考虑使用基于范围的 for 循环。 - user2672107
这个迭代器类别参考链接(http://en.cppreference.com/w/cpp/iterator#Iterator_categories)可能会对你有所帮助。 - Some programmer dude
2
非常相关:https://dev59.com/Umw15IYBdhLWcg3wWqV0 - Rakete1111
3个回答

40

operator<仅支持随机访问迭代器std::vector::iterator是一个随机访问迭代器,因此在您的示例中,i != vec.end()i < vec.end()都受支持且有效,并且不会产生任何区别。

如果您有一个容器不支持随机访问迭代器(例如std::list),i < list.end() 将无法编译。

一般建议仅在必要时使用后缀递增,因为当迭代器非平凡时,它可能会创建一个不必要的副本,所以++i更加简洁,速度也更快。

此外,如果循环调用的函数在此翻译单元中无法获得定义,则vec.end()将在每次循环迭代中重新从内存加载,这可能会导致不必要的缓存未命中。你可以通过将值保存到本地变量中来避免该重新加载,这样编译器就可以确定该局部变量对于任何其他函数都是不可访问的:

for(vector<int>::iterator i = vec.begin(), j = vec.end(); i < j; ++i)
    // ...

更好的是,你可以使用范围for循环,它避免了这些性能陷阱:

for(auto const& elem : vec)
    // ...

你能提供一个容器的例子,其中vec.end每次都会被重新计算吗?(我很好奇,因为我不想编写这样的代码) - sudo rm -rf slash
6
slow模式下,它会从内存中重新加载end(),而在fast模式下,则将其保存在寄存器中。 - Maxim Egorushkin
1
@sudorm-rfslash,问题在于编译器必须证明如果您调用.end()来缓存向量,则不会修改该向量,并且证明这一点通常很困难。如果您缓存它,则由来证明(否则您的代码可能会出现UB)。证明它有时很难。您更喜欢这两个中的哪一个是一个选择。 - Yakk - Adam Nevraumont
有时候值得反向迭代,只是为了避免重新加载end()...如果你正在索引向量,你需要begin()的值,所以你可以这样做:auto i = v.end(); while (i != v.begin()) { /* do something with *--i */ } - Will Crawford
@MaximEgorushkin 您是对的,当时已经是凌晨1点了,没想清楚。我们可以删除这些评论,并且永远不再提起吗?: o) - Will Crawford

11

STL标准库(容器、迭代器和算法)背后的整个哲学是尽量减少容器之间的编程差异。它们表现出不同的属性,但设计编程方式时力求相似。

这使它们更易于学习和更易于通用使用。这意味着您可以编写一个通用函数(或算法),并将其应用于任何其他容器(或尽可能多的容器)。

因此,如果可能的话,最好使用对所有容器和迭代器都通用的语法。

只有某些容器的迭代器允许进行<比较,但所有容器的迭代器都接受!=。因此,建议始终使用!=以保持一致性,并使您的代码轻松移植到其他容器中。


2
关于最后一段:更普遍地说,只有一些迭代器类型允许<比较,但除了简单的输出迭代器之外,所有迭代器类型都接受!=。容器是迭代器的一种来源,但它们并不是唯一的来源。 - Pete Becker

9

虽然对于std::vector而言可能没有太大的影响,但它确实有所作用。所有的迭代器都可以比较相等性,因此!=总是可行的。只有随机访问迭代器支持小于比较,std::vector也是如此,在你的情况下这并不是一个大问题。


2
并非所有的迭代器都可以进行相等比较,例如输出迭代器。 - Incomputable
@Incomputable 这个语句也出现在 https://dev59.com/Umw15IYBdhLWcg3wWqV0#6673775 - 如果它是错误的,那么那里的答案应该被修正(根据 http://en.cppreference.com/w/cpp/concept/InputIterator 它应该是安全的说“所有输入迭代器都可以进行相等比较”- 可能附带一个指向这个确切网站的链接) - Marco13

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