'for'循环vs Qt的'foreach'在C ++中

时间:2009-04-21 04:12:59

标签: c++ performance qt foreach for-loop

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

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
}

11 个答案:

答案 0 :(得分:148)

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

StackOverflow上关于这种方法或该方法是否更快的大量问题,认为在绝大多数情况下,代码大部分时间都在等待用户做某事。

如果 非常关注,请亲自为自己定位,并根据您的发现采取行动。

但我认为你很可能会发现,只有在最激烈的数据处理工作中,这个问题才有意义。差异可能只有几秒钟甚至那时,只有在处理大量元素时才会出现。

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

在完成功能之前花费时间进行优化并且可以正确分析,这主要是浪费时间。

答案 1 :(得分:22)

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

但是当然Qt的人已经调查了它并且实际上做了一些分析: http://blog.qt.io/blog/2009/01/23/iterating-efficiently/

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

答案 2 :(得分:15)

这无所谓。可能的情况是你的程序很慢,这不是问题。但是,应该注意的是,你并没有做出完全相同的比较。 Qt的foreach更类似于此(此示例将使用QList<QString>):

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

宏可以通过使用一些编译器扩展(如GCC的__typeof__)来获取传递的容器类型。还想象一下,boost BOOST_FOREACH在概念上非常相似。

你的例子不公平的原因是你的非Qt版本正在增加额外的工作。

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

话虽如此。 仍然无所谓。如果存在的话,这两段代码之间的时间差异可以忽略不计。不要浪费你的时间担心它。写下你发现的更清晰易懂的内容。

编辑:作为奖励,目前我非常支持C ++ 11版本的容器迭代,它简洁明了,简洁明了:

for(QString &s : Con) {
    // you code here
}

答案 3 :(得分:10)

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

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

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

答案 4 :(得分:5)

由于 Qt 5.7 {@ 1}}宏已弃用,因此Qt鼓励您使用C ++ 11 foreachhttp://doc.qt.io/qt-5/qtglobal.html#foreach

(有关差异的更多细节:https://www.kdab.com/goodbye-q_foreach/

答案 5 :(得分:4)

首先,我完全赞同“无所谓”的答案。选择最干净的解决方案,并优化它是否成为问题。

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

简单的for循环说你想要一个计数器i。您希望重复向此值i添加一个,并且只要它小于容器中的元素数,您就可以执行某些操作。

换句话说,plain for循环过度指定了问题。它增加了许多要求,而这些要求实际上并不是您要做的事情的一部分。你不关心循环计数器 care 。但是只要你编写一个for循环,就必须在那里。

另一方面,QT人员没有做出可能影响表现的额外承诺。它们只是保证迭代容器并对每个容器应用一个动作。

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

答案 6 :(得分:3)

来自Qt的foreach有一个更清晰的for循环恕我直言的语法,所以在这个意义上它更好。表现明智我怀疑它有什么。

你可以考虑使用BOOST_FOREACH,因为它是一个经过深思熟虑的循环,并且它是可移植的(并且可能会让它在某天进入C ++并且也是未来的证据)。

答案 7 :(得分:3)

答案 8 :(得分:2)

对于小型收藏品来说,它应该是重要的,而且预期往往更清晰。

然而,对于较大的收藏品,将在某些时候开始击败foreach。 (假设'at()'运算符有效。

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

答案 9 :(得分:1)

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

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

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

如果索引是文字内存偏移量(例如C ++),那么因为你要避免函数调用,所以应该稍微快一点。如果索引是一个间接就像一个调用,那么它应该是相同的。

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

答案 10 :(得分:0)

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