在C++中为循环编写迭代器的更好方法是什么

hyp*_*not 5 c++ boost iterator stl

对于一个非常简单的事情,例如在向量中打印每个元素,在C++中使用的更好的方法是什么?

我一直在用这个:

for (vector<int>::iterator i = values.begin(); i != values.end(); ++i)
Run Code Online (Sandbox Code Playgroud)

之前,但在我看到的Boost :: filesystem示例之一:

for (vec::const_iterator it(v.begin()), it_end(v.end()); it != it_end; ++it)
Run Code Online (Sandbox Code Playgroud)

对我来说,它看起来更复杂,我不明白为什么它比我一直使用的更好.

你能告诉我为什么这个版本会更好吗?或者对于像矢量打印元素这样的简单事情无关紧要?

是否i != values.end()使迭代慢?

还是const_iteratorvs iterator?const_iterator在这样的循环中更快吗?

Ker*_* SB 10

  1. Foo x = y;并且Foo x(y);是等价的,所以请根据自己的喜好使用.

  2. end无论如何,提升出循环可能是也可能不是编译器会做的事情,无论如何,它明确表示容器端没有改变.

  3. 如果你不打算修改元素,请使用const-iterators,因为这就是它们的意思.

for (MyVec::const_iterator it = v.begin(), end = v.end(); it != end; ++it)
{
  /* ... */
}
Run Code Online (Sandbox Code Playgroud)

在C++ 0x中,使用auto+ cbegin():

for (auto it = v.cbegin(), end = v.cend(); it != end; ++it)
Run Code Online (Sandbox Code Playgroud)

(也许你想使用现成的容器漂亮打印机?)

  • `cbegin()`返回一个const_iterator,所以你可以将它与`auto`一起使用.如果你说`auto it = v.begin()`你得到一个非const迭代器. (2认同)

Ton*_*roy 6

for (vector<int>::iterator i = values.begin(); i != values.end(); ++i)
Run Code Online (Sandbox Code Playgroud)

... ... VS

for (vec::const_iterator it(v.begin()), it_end(v.end()); it != it_end; ++it)
Run Code Online (Sandbox Code Playgroud)

对我来说[后者,在增强中看到]看起来更复杂,我不明白为什么它比我一直使用的更好.

我会说,对于那些没有某些特定理由喜欢后者的人来说,它会使人们感到歪曲,这看起来会更复杂.但让我们继续讨论为什么它会更好......

你能告诉我为什么这个版本会更好吗?或者对于像矢量打印元素这样的简单事情无关紧要?i!= values.end()会使迭代变慢吗?

  • it_end

    • 性能:作为循环的开始只it_end获取end()一次值.对于计算end()费用过高的任何容器,只调用一次可以节省CPU时间.对于任何中途不错的真实C++标准库,所有end()函数都不执行任何计算,并且可以内联以获得相同的性能.在实践中,除非有可能需要放入一个非标准的容器,这个容器的end()功能更加昂贵,所以end()在优化的代码中明确地"缓存"没有任何好处.

      这是有趣的,因为这意味着对于vectorsize()可能需要小的计算-概念性地减去begin()end()再除以sizeof(value_type)(编译器刻度隐期间指针运算由大小),例如GCC 4.5.2:

      size_type size() const
      { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }

    • 维护:如果代码演变为插入或擦除循环内的元素(显然是迭代器本身没有失效 - 对于映射/集合/列表等是合理的),这是另一个维护点(因此错误 -如果缓存的end()值也需要明确重新计算,则为俯卧.

  • 一个小细节,但这里vec必须是一个typedef,而恕我直言通常最好使用typedef作为容器,因为它放松了容器类型的耦合,并且可以访问迭代器类型.

  • type identifier(expr)

    • 风格和纪录片重点:type identifier(expr)更直接地指示构造函数调用type identifier = expr,这是一些人喜欢这种形式的主要原因.我通常更喜欢后者,因为我喜欢强调赋值 ...它在视觉上是明确的,而函数调用符号用于很多事情.

    • 近等价: 对于大多数类,无论如何都调用相同的构造函数,如果type有类型的显式构造函数expr,则在=使用时将传递它.更糟糕的是,一些其他转换可能允许使用不太理想的构造函数.例如,X x = 3.14;会传递explicit X::X(double);给匹配X::X(int)- 你可能会得到一个不那么精确(或者只是完全错误)的结果 - 但是我还没有被这样的问题所困扰,所以它非常理论化!

或者是const_iterator与迭代器?const_iterator在这样的循环中更快吗?

对于标准集装箱,const_iteratoriterator执行相同,但后者意味着你要为你遍历修改元素的能力.使用const_iterator您不打算这样做的文档,编译器将捕获尝试修改的迭代器的任何矛盾用法.例如,当您打算增加迭代器本身时,您将无法意外地增加迭代器地址的值.

鉴于C++ 0x已在其他答案中提及 - 但只有autocbegin/ 的增量收益,cend还有一个新的表示法支持:

for (const Foo& foo: container)
    // use foo...
Run Code Online (Sandbox Code Playgroud)