【问题标题】:Vector iterators < or !=向量迭代器 < 或 !=
【发布时间】:2018-07-09 07:13:21
【问题描述】:

在谈论for 循环中的向量迭代器时,谁能帮我理解!=&lt; 是否有很大区别?

我的意思是,不管你用!=&lt;,结果应该是一样的吧?

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

我知道最常用的方法是使用!=,但如果使用&lt; 会不会是个大问题?

【问题讨论】:

标签: c++ vector iterator


【解决方案1】:

operator&lt; 仅支持 random access iteratorsstd::vector::iterator 是一个随机访问迭代器,因此 i != vec.end()i &lt; vec.end() 均受支持且有效,并且在您的示例中没有任何区别。

如果您的容器不支持随机访问迭代器(例如std::list),i &lt; list.end() 将无法编译。

一般建议是仅在必要时使用后缀增量,因为它可能会在迭代器不平凡时创建不必要的副本,因此++i 更简洁,可能更快。

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

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

更好的是,您可能希望使用 range-for 循环来避免这些性能缺陷:

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

【讨论】:

  • 您能否提供一个容器示例,其中 vec.end 每次都会重新计算? (我很好奇,因为我不想写那样的代码)
  • @sudorm-rfslash godbolt.org/g/VyQMkH - 在slow 它从内存重新加载end(),在fast 它保存在一个寄存器中。
  • @sudorm-rfslash 所以,如果你调用.end() 来缓存它,编译器必须证明向量没有被修改,并证明这是经常很难。如果您缓存它,则由 来证明这一点(或者您的代码有 UB 风险)。证明它有时是困难的。您更喜欢这两者中的哪一个。
  • 有时值得向后迭代以避免重新加载 end() ...如果您要索引向量,则需要 begin() 的值,因此您可以执行 @987654337 @
  • @MaximEgorushkin 你是对的,现在是凌晨 1 点左右,没有思考。我们可以删除这些 cmets 并且永远不提吗? :o)
【解决方案2】:

标准库的STL 部分(容器、迭代器和算法)背后的整个理念是尽量减少容器之间的程序差异。它们表现出不同的属性,但您对它们的编程方式被设计为尽可能相似。

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

考虑到这一点,使用所有容器和迭代器通用的语法是有益的在可能的情况下

只有一些容器的迭代器允许&lt; 比较,但所有容器的迭代器接受!=。出于这个原因,我建议始终使用 != 以保持一致性并便于您的代码轻松移植到不同的容器。

【讨论】:

  • 关于最后一段:更一般地说,只有一些迭代器类型允许&lt; 比较,但所有迭代器类型(除了简单的输出迭代器)都接受!=。容器是迭代器的一种来源,但它们并不是唯一的来源。
【解决方案3】:

它确实有所作为,但不适用于std::vector。所有的迭代器都是相等的,所以!= 总是可以工作的。只有随机访问迭代器无法比较,std::vector 也是如此,所以在你的情况下这不是一个大问题。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2011-11-15
  • 2017-08-29
  • 2013-12-16
  • 1970-01-01
  • 1970-01-01
  • 2013-02-07
  • 1970-01-01
相关资源
最近更新 更多