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

时间:2011-07-12 22:38:01

标签: c++ boost stl iterator

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

我一直在用这个:

for (vector<int>::iterator i = values.begin(); i != values.end(); ++i)

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

for (vec::const_iterator it(v.begin()), it_end(v.end()); it != it_end; ++it)

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

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

i != values.end()使迭代变慢吗?

或者是const_iterator vs iterator? const_iterator在这样的循环中更快吗?

5 个答案:

答案 0 :(得分:10)

  1. Foo x = y;Foo x(y);相同,因此请根据您的喜好使用。

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

  3. 如果您不打算修改元素,请使用const-iterators,因为这就是它们的含义。

  4. for (MyVec::const_iterator it = v.begin(), end = v.end(); it != end; ++it)
    {
      /* ... */
    }
    

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

    for (auto it = v.cbegin(), end = v.cend(); it != end; ++it)
    

    (也许您想使用现成的container pretty-printer?)

答案 1 :(得分:6)

for (vector<int>::iterator i = values.begin(); i != values.end(); ++i)

... ... VS

for (vec::const_iterator it(v.begin()), it_end(v.end()); it != it_end; ++it)
  

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

我会说,对于任何没有特定理由喜欢后者的人来说,它会更加复杂,从而扭曲了感知。但让我们继续讨论为什么它会更好......

  

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

  • it_end

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

      这很有意思,因为vector表示size()可能需要一个小的计算 - 概念上从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更直接地表示构造函数调用,这是某些人更喜欢该形式的主要原因。我通常更喜欢后者,因为我喜欢强调赋值的 sense ...它在视觉上是明确的,而函数调用符号用于很多事情。

    • 近等效:对于大多数类,无论如何都调用相同的构造函数,但是如果type具有expr类型的显式构造函数{1}},如果使用=,它将被传递。更糟糕的是,一些其他转换可能允许使用不太理想的构造函数。例如,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...

答案 2 :(得分:3)

要在矢量中打印项目,您不应使用上述任何一项(至少是IMO)。

我建议这样的事情:

std::copy(values.begin(), values.end(), 
          std::ostream_iterator<T>(std::cout, "\n"));

答案 3 :(得分:0)

您只能通过索引

访问它们
int main(int argc, char* argv[])
{
    std::vector<int> test;

    test.push_back(10);
    test.push_back(11);
    test.push_back(12);

    for(int i = 0; i < test.size(); i++)
        printf("%d\n", test[i]);
}

打印出来: 10 11 12

答案 4 :(得分:0)

我认为这不重要。在内部,它们做同样的事情,所以编译器应该优化它。我会亲自使用第一个版本,因为它更加清晰,因为它紧跟着for循环结构。

for (vector<int>::iterator i = values.begin(); i != values.end(); ++i)