C++;迭代器&;循环优化 我看到很多C++代码,看起来像这样: for( const_iterator it = list.begin(), const_iterator ite = list.end(); it != ite; ++it)

C++;迭代器&;循环优化 我看到很多C++代码,看起来像这样: for( const_iterator it = list.begin(), const_iterator ite = list.end(); it != ite; ++it),c++,optimization,compiler-construction,coding-style,iterator,C++,Optimization,Compiler Construction,Coding Style,Iterator,与更简洁的版本相反: for( const_iterator it = list.begin(); it != list.end(); ++it) 这两个惯例在速度上有什么不同吗?由于list.end()只被调用一次,所以第一个函数的速度会稍微快一点。但由于迭代器是常量,编译器似乎会将此测试从循环中拉出来,为这两个测试生成等效的程序集。第一个可能总是更快,但如果您认为这会有所不同,请始终首先分析,以查看哪个更快,以及速度有多快 在这两种情况下,编译器可能都能够内联调用end(),尽管

与更简洁的版本相反:

for( const_iterator it = list.begin();
     it != list.end(); ++it)

这两个惯例在速度上有什么不同吗?由于list.end()只被调用一次,所以第一个函数的速度会稍微快一点。但由于迭代器是常量,编译器似乎会将此测试从循环中拉出来,为这两个测试生成等效的程序集。

第一个可能总是更快,但如果您认为这会有所不同,请始终首先分析,以查看哪个更快,以及速度有多快


在这两种情况下,编译器可能都能够内联调用
end()
,尽管如果
end()
足够复杂,它可能会选择不内联调用。然而,关键的优化是编译器是否能够执行。我假设,在大多数情况下,编译器无法确定
end()
的值在循环的迭代过程中不会改变,在这种情况下,编译器除了在每次迭代后调用
end()
之外别无选择。

我会选择最简洁易读的选项。不要试图猜测编译器及其可能执行的优化。请记住,绝大多数代码对总体性能绝对没有影响,因此只有在代码的性能关键部分,您才应该花时间分析它并选择适当有效的源代码表示形式


具体参考您的示例,第一个版本创建了
end()
迭代器的副本,调用迭代器对象的复制构造函数运行的任何代码。STL容器通常包含内联
end()
函数,因此编译器有很多机会优化第二个版本,即使您不想帮助它。哪一个最好?测量它们。

理论上,编译器可以将第二个版本优化为第一个版本(显然,假设容器在循环过程中没有变化)


在实践中,我在分析时间关键型代码时发现了几个类似的情况,其中我的编译器完全无法将不变计算从循环条件中提升出来。因此,虽然在大多数情况下稍微简洁一点的版本是可以的,但在我真正关心性能的情况下,我并不依赖编译器对其进行合理的处理。

您可以使第一个版本更简洁,并充分利用这两个方面:

for( const_iterator it = list.begin(), ite = list.end();
     it != ite; ++it)

另外,迭代器不是常量,它们是常量引用的迭代器。有很大的不同。

但是这两个版本不一样。在第二个版本中,它每次都将迭代器与
list.end()
进行比较,并且
list.end()
的计算结果可能会在循环过程中发生变化。当然,现在不能通过const_迭代器
it
修改
list
;但是没有什么可以阻止循环中的代码直接调用
list
上的方法并对其进行变异,这可能(取决于
list
是什么样的数据结构)改变最终迭代器。因此,在某些情况下,预先存储结束迭代器可能是不正确的,因为当您到达它时,它可能不再是正确的结束迭代器。

我总是首选第一个。尽管有内联函数、编译器优化和相对较小的容器大小(在我的例子中,通常最大为20-25项),但在性能方面并没有太大的区别

const_iterator it = list.begin();
const_iterator endIt = list.end();

for(; it != endIt ; ++it)
{//do something
}
但最近我在任何可能的地方都使用了更多。它的优化循环有助于使代码看起来比其他两个更可读

std::for_each(list.begin(), list.end(), Functor());

仅当无法使用
std::for_each
时,我才会使用循环。(例如:
std::for_每个
都不允许您中断循环,除非抛出异常)。

Aah,人们似乎在猜测。在调试器中打开您的代码&您将看到对begin()、end()等的调用都经过了优化。没有必要使用版本1。用VisualC++编译器测试了Pulopt.

考虑这个例子:

for (const_iterator it = list.begin(); it != list.end(); ++list)
{
    if (moonFull())
        it = insert_stuff(list);
    else
        it = erase_stuff(list);
}
在这种情况下,需要在循环中调用list.end(),编译器不会对此进行优化

在编译器可以证明end()总是返回相同值的其他情况下,可以进行优化


如果我们讨论的是STL容器,那么我认为任何好的编译器都可以在编程逻辑不需要多个end()调用的情况下优化多个end()调用。但是,如果您有一个自定义容器,并且end()的实现不在同一个转换单元中,则必须在链接时进行优化。对于链接时间优化,我知之甚少,但我敢打赌,大多数链接者不会做这样的优化。

< p>我只需记录一下,C++标准规定在任何容器类型上调用<代码>开始/代码>和<代码>结束()/代码>(无论是代码>矢量< /代码>,代码>列表>代码>代码>地图>代码>等。必须只花费恒定的时间。在实践中,如果在启用优化的情况下编译,这些调用几乎肯定会内联到单指针比较

请注意,本保证不一定适用于其他供应商提供的“容器”,这些容器实际上不符合本标准第23章中规定的容器形式要求(例如单链表
slist

  • 在压力条件下对其进行采样,看看您是否经常使用**此代码***.
    如果不是,则无所谓

  • 如果是,请查看拆卸或单步拆卸。
    这就是如何判断哪个更快

  • 你必须小心这些迭代器。
    它们可能会被优化成好的机器代码,但通常不会,它们会成为时间的消耗者

    **(其中“in”指实际存在于其中,或被称为 // assuming list -- cannot cache end() for vector iterator it(c.begin()), end(c.end()); while(it != end) { if (should_remove(*it)) it = c.erase(it); else ++it; }