56

哪个更好(或更快),是 C++for循环还是foreachQt 提供的运算符?例如,以下条件

QList<QString> listofstrings;

哪个更好?

foreach(QString str, listofstrings)
{
    //code
}

或者

int count = listofstrings.count();
QString str = QString();
for(int i=0;i<count;i++)
{
    str = listofstrings.at(i);
    //Code
}
4

11 回答 11

152

在大多数情况下,这真的无关紧要。

StackOverflow 上关于这种方法或那种方法是否更快的大量问题掩盖了这样一个事实,即在绝大多数情况下,代码大部分时间都在等待用户做某事。

如果您真的很担心,请自行分析并根据您的发现采取行动。

但我认为您很可能会发现,只有在最密集的数据处理繁重的工作中,这个问题才有意义。差异很可能只有几秒钟,即使那样,也只有在处理大量元素时。

让您的代码首先工作。然后让它快速工作(并且只有当你发现实际的性能问题时)。

在您完成功能并可以正确配置之前花在优化上的时间主要是浪费时间。

于 2009-04-21T04:19:41.613 回答
25

首先,我只想说我同意 Pax,并且速度可能不会进入它。foreach 基于可读性赢得了胜利,这在 98% 的情况下就足够了。

但是当然 Qt 的人已经研究过了,实际上做了一些分析: http ://blog.qt.io/blog/2009/01/23/iterating-efficiently/

从中吸取的主要教训是:在只读循环中使用 const 引用,因为它避免了临时实例的创建。它还使循环的目的更加明确,无论您使用哪种循环方法。

于 2009-04-21T16:07:52.800 回答
19

真的没关系。奇怪的是,如果你的程序很慢,这不是问题。但是,应该注意的是,您并没有进行完全平等的比较。Qtforeach与此更相似(此示例将使用QList<QString>):

for(QList<QString>::iterator it = Con.begin(); it != Con.end(); ++it) {
    QString &str = *it;
    // your code here
}

宏能够通过使用一些编译器扩展(如 GCC's __typeof__)来获得传递的容器类型来做到这一点。还可以想象 boostBOOST_FOREACH在概念上非常相似。

您的示例不公平的原因是您的非 Qt 版本增加了额外的工作。

您正在索引而不是真正迭代。如果您使用的是具有非连续分配的类型(我怀疑这可能是这种情况QList<>),那么索引将更加昂贵,因为代码必须计算第 n 个项目的“位置”。

话虽如此。还是没关系。如果存在的话,这两段代码之间的时间差异将可以忽略不计。不要浪费时间担心它。写下你觉得更清晰易懂的。

编辑:作为奖励,目前我强烈支持 C++11 版本的容器迭代,它干净、简洁、简单:

for(QString &s : Con) {
    // you code here
}
于 2009-04-21T17:27:54.590 回答
17

由于Qt 5.7已弃用该foreach宏,Qt 鼓励您改用 C++11 for
http://doc.qt.io/qt-5/qtglobal.html#foreach

(有关此处差异的更多详细信息:https ://www.kdab.com/goodbye-q_foreach/ )

于 2017-08-16T11:17:13.323 回答
13

我不想回答哪个更快的问题,但我确实想说哪个更好。

Qt 的 foreach 最大的问题是它在迭代之前需要一个容器的副本。您可以说“这无关紧要,因为 Qt 类已被引用”,但因为使用了副本,您实际上根本不会更改原始容器。

总之,Qt 的 foreach 只能用于只读循环,因此应该避免使用。Qt 很乐意让您编写一个 foreach 循环,您认为该循环会更新/修改您的容器,但最终所有更改都会被丢弃。

于 2009-04-25T14:13:37.100 回答
4

首先,我完全同意“没关系”的回答。选择最干净的解决方案,并在它成为问题时进行优化。

但另一种看待它的方式是,最快的解决方案通常是最准确地描述您的意图的解决方案。在这种情况下,QT 的 foreach 表示您希望对容器中的每个元素应用一些操作。

一个普通的 for 循环说你想要一个 counter i。你想在这个值 i 上重复加一,只要它小于容器中元素的数量,你就想执行一些动作。

换句话说,普通的 for 循环过度指定了问题。它增加了许多实际上并不是您正在尝试做的事情的一部分。你不关心循环计数器。但是一旦你写了一个 for 循环,它就必须在那里。

另一方面,QT 人没有做出任何可能影响性能的额外承诺。他们只是保证遍历容器并对每个容器应用一个动作。

换句话说,通常最干净、最优雅的解决方案也是最快的。

于 2009-04-21T16:53:14.953 回答
3

恕我直言,Qt 中的 foreach 对 for 循环有更清晰的语法,因此在这个意义上它更好。性能方面,我怀疑里面有什么东西。

您可以考虑改用BOOST_FOREACH,因为它是一个经过深思熟虑的 for 循环,而且它是可移植的(并且可能有一天会进入 C++ 并且也是未来的证明)。

于 2009-04-21T04:21:28.100 回答
3

可以在http://richelbilderbeek.nl/CppExerciseAddOneAnswer.htm找到一个基准及其结果

恕我直言(以及这里的许多其他人)它(即速度)并不重要。

但请随意得出自己的结论。

于 2010-07-25T09:52:15.190 回答
2

对于小型集合,它应该很重要,并且 foreach 往往更清晰。

但是,对于较大的集合,for 将在某个时候开始击败 foreach。(假设 'at()' 运算符是有效的。

如果这真的很重要(我假设它是因为你在问),那么最好的办法就是衡量它。分析器应该可以解决问题,或者您可以使用一些工具构建测试版本。

于 2009-04-21T04:26:10.833 回答
0

我希望 foreach 在某些情况下名义上的工作速度更快,而在其他情况下则大致相同,除非项目是实际数组,在这种情况下性能差异可以忽略不计。

如果它是在枚举数之上实现的,它可能比直接索引更有效,具体取决于实现。它不太可能降低效率。例如,如果有人将平衡树公开为既可索引又可枚举,那么 foreach 会更快。这是因为每个索引都必须独立找到引用的项目,而枚举器具有当前节点的上下文,以便更有效地导航到下一个实体。

如果你有一个实际的数组,那么它取决于语言和类的实现,foreach 是否会比 for 更快。

如果索引是文字内存偏移量(例如 C++),那么 for 应该稍微快一些,因为您避免了函数调用。如果索引就像调用一样是间接的,那么它应该是相同的。

说了这么多……我发现在这里很难找到一个概括的案例。这是您应该寻找的最后一种优化,即使您的应用程序中存在性能问题。如果你有一个性能问题可以通过改变你的迭代方式来解决,那么你就没有真正的性能问题。你有一个BUG,因为有人写了一个非常糟糕的迭代器,或者一个非常糟糕的索引器。

于 2009-04-21T04:50:07.483 回答
0

您可能会查看 STL 的for_each函数。我不知道它是否会比您提供的两个选项更快,但它比 Qt foreach 更标准化,并且避免了您在使用常规 for 循环时可能遇到的一些问题(即越界索引和困难将循环转换为不同的数据结构)。

于 2009-04-21T15:09:01.333 回答