繁体   English   中英

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

[英]'for' loop vs Qt's 'foreach' in C++

哪个更好(或更快),一个C ++ for循环或Qt提供的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
}

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

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

如果你真的关心,简介为自己和作用于你的发现。

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

让代码先运行 然后让它快速运行 (并且只有在您发现实际性能问题时)。

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

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

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

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

这没关系 可能的情况是你的程序很慢,这不是问题。 但是,应该注意的是,你并没有做出完全相同的比较。 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”。

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

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

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

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

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

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

由于Qt的5.7 foreach宏已被弃用,QT鼓励您使用C ++ 11 for替代。
http://doc.qt.io/qt-5/qtglobal.html#foreach

(有关差异的更多详细信息,请访问: https//www.kdab.com/goodbye-q_foreach/

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

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

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

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

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

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

关于此的基准及其结果可以在http://richelbilderbeek.nl/CppExerciseAddOneAnswer.htm找到。

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

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

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

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

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

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

如果这非常重要(我假设它是你要求的那样),那么最好的办法就是衡量它。 分析器应该可以解决问题,或者您可以使用一些检测来构建测试版本。

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

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM