简体   繁体   English

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

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

Which is better (or faster), a C++ for loop or the foreach operator provided by Qt? 哪个更好(或更快),一个C ++ for循环或Qt提供的foreach运算符? For example, the following condition 例如,以下条件

QList<QString> listofstrings;

Which is better? 哪个更好?

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

or 要么

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

It really doesn't matter in most cases. 在大多数情况下,这无关紧要。

The large number of questions on StackOverflow regarding whether this method or that method is faster, belie the fact that, in the vast majority of cases, code spends most of its time sitting around waiting for users to do something. 关于这种方法或该方法是否更快的StackOverflow上的大量问题,认为在绝大多数情况下,代码花费大部分时间等待用户做某事。

If you are really concerned, profile it for yourself and act on what you find. 如果你真的关心,简介为自己和作用于你的发现。

But I think you'll most likely find that only in the most intense data-processing-heavy work does this question matter. 但我认为你很可能会发现,只有在最激烈的数据处理工作中,这个问题才能解决。 The difference may well be only a couple of seconds and even then, only when processing huge numbers of elements. 只有在处理大量元素时,差异可能只有几秒甚至更长时间。

Get your code working first . 让代码先运行 Then get it working fast (and only if you find an actual performance issue). 然后让它快速运行 (并且只有在您发现实际性能问题时)。

Time spent optimising before you've finished the functionality and can properly profile, is mostly wasted time. 在完成功能之前花费时间进行优化并且可以正确分析,这主要是浪费时间。

First off, I'd just like to say I agree with Pax, and that the speed probably doesn't enter into it. 首先,我只想说我同意Pax,并且速度可能不会进入它。 foreach wins hands down based on readability, and that's enough in 98% of cases. foreach基于可读性赢得了胜利,这在98%的情况下都足够了。

But of course the Qt guys have looked into it and actually done some profiling: http://blog.qt.io/blog/2009/01/23/iterating-efficiently/ 但是当然Qt的人已经调查了它并且实际上做了一些分析: http//blog.qt.io/blog/2009/01/23/iterating-efficiently/

The main lesson to take away from that is: use const references in read only loops as it avoids the creation of temporary instances. 从中学到的主要教训是:在只读循环中使用const引用,因为它避免了临时实例的创建。 It also make the purpose of the loop more explicit, regardless of the looping method you use. 无论您使用何种循环方法,它还使循环的目的更明确。

It really doesn't matter . 这没关系 Odds are if your program is slow, this isn't the problem. 可能的情况是你的程序很慢,这不是问题。 However, it should be noted that you aren't make a completely equal comparison. 但是,应该注意的是,你并没有做出完全相同的比较。 Qt's foreach is more similar to this (this example will use QList<QString> ): Qt的foreach更类似于此(此示例将使用QList<QString> ):

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

The macro is able to do this by using some compiler extensions (like GCC's __typeof__ ) to get the type of the container passed. 宏可以通过使用一些编译器扩展(如GCC的__typeof__ )来获取传递的容器类型。 Also imagine that boost's BOOST_FOREACH is very similar in concept. 还想象一下boost的BOOST_FOREACH在概念上非常相似。

The reason why your example isn't fair is that your non-Qt version is adding extra work. 你的例子不公平的原因是你的非Qt版本正在增加额外的工作。

You are indexing instead of really iterating. 您正在编制索引而不是实际迭代。 If you are using a type with non-contiguous allocation (I suspect this might be the case with QList<> ), then indexing will be more expensive since the code has to calculate "where" the n-th item is. 如果您使用的是具有非连续分配的类型(我怀疑这可能是QList<>的情况),那么索引将更加昂贵,因为代码必须计算第n个项目的“where”。

That being said. 话虽如此。 It still doesn't matter. 仍然没关系。 The timing difference between those two pieces of code will be negligible if existent at all. 如果存在的话,这两段代码之间的时间差异可以忽略不计。 Don't waste your time worrying about it. 不要浪费你的时间担心它。 Write whichever you find more clear and understandable. 写下你发现的更清晰易懂的内容。

EDIT: As a bonus, currently I strongly favor the C++11 version of container iteration, it is clean, concise and simple: 编辑:作为奖励,目前我非常支持C ++ 11版本的容器迭代,它简洁明了:

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

I don't want to answer the question which is faster, but I do want to say which is better. 我不想回答更快的问题,但我想说哪个更好。

The biggest problem with Qt's foreach is the fact that it takes a copy of your container before iterating over it. Qt的foreach最大的问题是它在迭代之前需要一个容器的副本。 You could say 'this doesn't matter because Qt classes are refcounted' but because a copy is used you don't actually change your original container at all. 您可以说'这无关紧要,因为Qt类已被重新计算',但由于使用了副本,您根本不会实际更改原始容器。

In summary, Qt's foreach can only be used for read-only loops and thus should be avoided. 总之,Qt的foreach只能用于只读循环,因此应该避免使用。 Qt will happily let you write a foreach loop which you think will update/modify your container but in the end all changes are thrown away. Qt很乐意让你编写一个foreach循环,你认为它会更新/修改你的容器,但最后所有的变化都会被抛弃。

Since Qt 5.7 the foreach macro is deprecated, Qt encourages you to use the C++11 for instead. 由于Qt的5.7 foreach宏已被弃用,QT鼓励您使用C ++ 11 for替代。
http://doc.qt.io/qt-5/qtglobal.html#foreach http://doc.qt.io/qt-5/qtglobal.html#foreach

(more details about the difference here : https://www.kdab.com/goodbye-q_foreach/ ) (有关差异的更多详细信息,请访问: https//www.kdab.com/goodbye-q_foreach/

First, I completely agree with the answer that "it doesn't matter". 首先,我完全赞同“无所谓”的答案。 Pick the cleanest solution, and optimize if it becomes a problem. 选择最干净的解决方案,并优化是否成为问题。

But another way to look at it is that often, the fastest solution is the one that describes your intent most accurately. 但另一种看待它的方法是,最快的解决方案通常是最准确地描述您的意图的解决方案。 In this case, QT's foreach says that you'd like to apply some action for each element in the container. 在这种情况下,QT的foreach表示您希望对容器中的每个元素应用一些操作。

A plain for loop say that you'd like a counter i . 一个普通的循环说你想要一个反击i You want to repeatedly add one to this value i, and as long as it is less than the number of elements in the container, you would like to perform some action. 您希望重复向此值i添加一个,并且只要它小于容器中的元素数,您就可以执行某些操作。

In other words, the plain for loop overspecifies the problem. 换句话说,plain for循环过度指定了问题。 It adds a lot of requirements that aren't actually part of what you're trying to do. 它增加了许多要求,而这些要求实际上并不是您要做的事情的一部分。 You don't care about the loop counter. 你不关心循环计数器。 But as soon as you write a for loop, it has to be there. 但是只要你编写一个for循环,就必须在那里。

On the other hand, the QT people have made no additional promises that may affect performance. 另一方面,QT人员没有做出可能影响绩效的额外承诺。 They simply guarantee to iterate through the container and apply an action to each. 它们只是保证迭代容器并对每个容器应用一个动作。

In other words, often the cleanest and most elegant solution is also the fastest. 换句话说,通常最干净,最优雅的解决方案也是最快的。

A benchmark, and its results, on this can be found at http://richelbilderbeek.nl/CppExerciseAddOneAnswer.htm 关于此的基准及其结果可以在http://richelbilderbeek.nl/CppExerciseAddOneAnswer.htm找到。

IMHO (and many others here) it (that is speed) does not matter. 恕我直言(以及其他许多人)它(即速度)并不重要。

But feel free to draw your own conclusions. 但请随意得出自己的结论。

The foreach from Qt has a clearer syntax for the for loop IMHO, so it's better in that sense. 来自Qt的foreach有一个更清晰的for循环恕我直言的语法,所以在这个意义上它更好。 Performance wise I doubt there's anything in it. 表现明智我怀疑它有什么。

You could consider using the BOOST_FOREACH instead, as it is a well thought out fancy for loop, and it's portable (and presumably will make it's way into C++ some day and is future proof too). 您可以考虑使用BOOST_FOREACH ,因为它是一个经过深思熟虑的循环,并且它是可移植的(并且可能会让它在某天进入C ++并且也是未来的证明)。

For small collections, it should matter and foreach tends to be clearer. 对于小型馆藏来说,它应该是重要的,而且预期往往更清晰。

However, for larger collections, for will begin to beat foreach at some point. 然而,对于较大的收藏品,将在某些时候开始击败foreach。 (assuming that the 'at()' operator is efficient. (假设'at()'运算符是有效的。

If this is really important (and I'm assuming it is since you are asking) then the best thing to do is measure it. 如果这非常重要(我假设它是你要求的那样),那么最好的办法就是衡量它。 A profiler should do the trick, or you could build a test version with some instrumentation. 分析器应该可以解决问题,或者您可以使用一些检测来构建测试版本。

I would expect foreach to work nominally faster in some cases, and the about same in others, except in cases where the items are an actual array in which case the performace difference is negligible. 我希望foreach在某些情况下名义上更快,而在其他情况下大致相同,除非项目是实际数组,在这种情况下,性能差异可以忽略不计。

If it is implemented on top of an enumerator, it may be more efficient than a straight indexing, depending on implementation. 如果它是在枚举器之上实现的,则它可能比直接索引更有效,具体取决于实现。 It's unlikely to be less efficient. 它不太可能效率低下。 For example, if someone exposed a balanced tree as both indexable and enumerable, then foreach will be decently faster. 例如,如果有人将平衡树暴露为可索引和可​​枚举的,那么foreach将会更加快速。 This is because each index will have to independently find the referenced item, while an enumerator has the context of the current node to more efficiently navigate to the next ont. 这是因为每个索引必须独立地找到引用的项,而枚举器具有当前节点的上下文以更有效地导航到下一个ont。

If you have an actual array, then it depends on the implementation of the language and class whether foreach will be faster for the same as for. 如果你有一个实际的数组,那么它取决于语言和类的实现是否foreach将更快与for。相同。

If indexing is a literal memory offset(such as C++), then for should be marginally faster since you're avoiding a function call. 如果索引是一个文字内存偏移量(例如C ++),那么因为你要避免函数调用,所以应该稍微快一点。 If indexing is an indirection just like a call, then it should be the same. 如果索引是一个间接,就像一个调用,那么它应该是相同的。

All that being said... I find it hard to find a case for generalization here. 所有这一切......我发现很难找到一个概括的案例。 This is the last sort of optimization you should be looking for, even if there is a performance problem in your application. 这是您应该寻找的最后一种优化,即使您的应用程序存在性能问题。 If you have a performance problem that can be solved by changing how you iterate, you don't really have a performance problem. 如果您遇到可以通过更改迭代方式来解决的性能问题,那么您实际上并没有遇到性能问题。 You have a BUG, because someone wrote either a really crappy iterator, or a really crappy indexer. 你有一个BUG,因为有人写了一个非常糟糕的迭代器,或者一个非常糟糕的索引器。

You might look at the STL's for_each function. 您可以查看STL的for_each函数。 I don't know whether it will be faster than the two options you present, but it is more standardized than the Qt foreach and avoids some of the problems that you may run into with a regular for loop (namely out of bounds indexing and difficulties with translating the loop to a different data structure). 我不知道它是否会比你提出的两个选项更快,但它比Qt foreach更标准化,并避免了你可能遇到的常规for循环的一些问题(即越界索引和困难)将循环转换为不同的数据结构)。

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

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