‘for’ loop vs ‘foreach’ de Qt en C ++

Quel est le meilleur (ou le plus rapide), une boucle C ++ for ou l’opérateur foreach fourni par Qt? Par exemple, la condition suivante

 QList listofssortingngs; 

Ce qui est mieux?

 foreach(QSsortingng str, listofssortingngs) { //code } 

ou

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

Cela n’a pas vraiment d’importance dans la plupart des cas.

Le grand nombre de questions sur StackOverflow concernant la rapidité avec laquelle cette méthode ou cette méthode est utilisée dément le fait que, dans la grande majorité des cas, le code passe le plus clair de son temps à attendre que les utilisateurs fassent quelque chose.

Si vous êtes vraiment concerné, faites le profil pour vous-même et agissez sur ce que vous trouvez.

Mais je pense que vous trouverez probablement que seul le travail le plus intense du traitement des données est important. La différence pourrait bien ne durer que quelques secondes et même alors, uniquement lors du traitement d’un grand nombre d’éléments.

Obtenez votre code en premier lieu . Ensuite, faites-le fonctionner rapidement (et seulement si vous trouvez un problème de performance).

Le temps passé à l’optimisation avant que vous ayez terminé la fonctionnalité et que vous puissiez correctement définir votre profil, c’est surtout du temps perdu.

Tout d’abord, je voudrais juste dire que je suis d’accord avec Pax, et que la vitesse n’y entre probablement pas. foreach gagne haut la main sur la lisibilité, et cela suffit dans 98% des cas.

Mais bien sûr, les gars de Qt l’ont examiné et ont fait du profilage: http://blog.qt.io/blog/2009/01/23/iterating-efficiently/

La principale leçon à en tirer est la suivante: utiliser des références const dans des boucles en lecture seule, car cela évite la création d’instances temporaires. Cela rend également l’objective de la boucle plus explicite, quelle que soit la méthode de bouclage utilisée.

Ça n’a vraiment pas d’importance . Les chances sont que si votre programme est lent, ce n’est pas le problème. Cependant, il convient de noter que vous ne faites pas une comparaison totalement égale. Le foreach de Qt ressemble plus à ceci (cet exemple utilisera QList ):

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

La macro est capable de faire cela en utilisant certaines extensions du compilateur (comme __typeof__ de GCC) pour obtenir le type du conteneur passé. Imaginez également que BOOST_FOREACH de boost a un BOOST_FOREACH très similaire.

La raison pour laquelle votre exemple n’est pas juste est que votre version non-Qt ajoute du travail supplémentaire.

Vous indexez au lieu de vraiment itérer. Si vous utilisez un type avec une allocation non contiguë (je suppose que cela pourrait être le cas avec QList<> ), l’indexation sera plus coûteuse puisque le code doit calculer “où” le n-ième élément.

Cela étant dit. Cela n’a toujours pas d’importance. La différence de temps entre ces deux parties de code sera négligeable si elle existe. Ne perdez pas votre temps à vous en soucier. Écrivez ce que vous trouvez plus clair et compréhensible.

EDIT: En bonus, je privilégie actuellement la version C ++ 11 de l’itération de conteneur, elle est propre, concise et simple:

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

Je ne veux pas répondre à la question qui est plus rapide, mais je veux dire quelle est la meilleure.

Le plus gros problème avec le fort de Qt est le fait qu’il prend une copie de votre conteneur avant de l’itérer. Vous pourriez dire «cela n’a pas d’importance, car les classes Qt sont recalculées», mais comme une copie est utilisée, vous ne changez pas du tout votre conteneur d’origine.

En résumé, le foreach de Qt ne peut être utilisé que pour les boucles en lecture seule et doit donc être évité. Qt vous laissera volontiers écrire une boucle foreach qui, selon vous, mettra à jour / modifiera votre conteneur mais à la fin, toutes les modifications seront supprimées.

Tout d’abord, je suis tout à fait d’accord avec la réponse selon laquelle «peu importe». Choisissez la solution la plus propre et optimisez si cela devient un problème.

Mais une autre façon de voir les choses est que souvent, la solution la plus rapide est celle qui décrit le mieux votre intention. Dans ce cas, foreach de QT dit que vous souhaitez appliquer une action pour chaque élément du conteneur.

Un simple pour la boucle dire que vous voudriez un compteur i . Vous souhaitez append plusieurs fois une valeur à cette valeur i, et tant que le nombre d’éléments contenus dans le conteneur est inférieur à celui souhaité, vous souhaitez effectuer certaines actions.

En d’autres termes, la plaine pour la boucle sur-spécifie le problème. Il ajoute beaucoup d’exigences qui ne font pas réellement partie de ce que vous essayez de faire. Vous ne vous souciez pas du compteur de boucles. Mais dès que vous écrivez une boucle for, elle doit être là.

D’autre part, les responsables de QT n’ont fait aucune promesse supplémentaire susceptible d’affecter les performances. Ils garantissent simplement de parcourir le conteneur et d’appliquer une action à chacun.

En d’autres termes, la solution la plus propre et la plus élégante est souvent la plus rapide.

Le foreach de Qt a une syntaxe plus claire pour l’IMHO for loop, donc c’est mieux en ce sens. Sage de performance Je doute qu’il y ait quelque chose dedans.

Vous pourriez envisager d’utiliser BOOST_FOREACH à la place, car c’est une fantaisie bien pensée pour la boucle, et elle est portable (et va probablement faire son entrée en C ++ un jour et sera également à l’épreuve du futur).

Un benchmark et ses résultats à ce sujet peuvent être trouvés sur http://richelbilderbeek.nl/CppExerciseAddOneAnswer.htm

IMHO (et beaucoup d’autres ici) cela (c’est la vitesse) n’a pas d’importance.

Mais n’hésitez pas à tirer vos propres conclusions.

Depuis Qt 5.7, la macro foreach est obsolète, Qt vous encourage à utiliser C ++ 11 for place.
http://doc.qt.io/qt-5/qtglobal.html#foreach

(plus de détails sur la différence ici: https://www.kdab.com/goodbye-q_foreach/ )

Pour les petites collections, cela devrait avoir de l’importance et la foreach a tendance à être plus claire.

Cependant, pour les grandes collections, car va commencer à battre à un certain point. (en supposant que l’opérateur ‘at ()’ est efficace.

Si c’est vraiment important (et je suppose que c’est depuis que vous le demandez), la meilleure chose à faire est de le mesurer. Un profileur devrait faire l’affaire, ou vous pourriez construire une version de test avec des instruments.

Je m’attendrais à ce que chaque élément fonctionne plus vite dans certains cas, et le même dans d’autres, sauf dans les cas où les éléments sont un tableau réel, auquel cas la différence de performances est négligeable.

S’il est implémenté au-dessus d’un énumérateur, il peut être plus efficace qu’une indexation directe, en fonction de l’implémentation. Il est peu probable qu’il soit moins efficace. Par exemple, si quelqu’un a exposé un arbre équilibré à la fois indexable et énumérable, alors foreach sera décemment plus rapide. En effet, chaque index devra rechercher indépendamment l’élément référencé, tandis qu’un énumérateur aura le contexte du nœud actuel pour naviguer plus efficacement vers le suivant.

Si vous avez un tableau réel, cela dépend de l’implémentation du langage et de la classe si foreach sera plus rapide pour le même que pour.

Si l’indexation est un décalage de mémoire littéral (tel que C ++), alors devrait être légèrement plus rapide puisque vous évitez un appel de fonction. Si l’indexation est une indirection comme un appel, alors elle devrait être la même.

Tout cela étant dit … j’ai du mal à trouver un cas de généralisation ici. C’est le dernier type d’optimisation que vous devriez rechercher, même s’il existe un problème de performance dans votre application. Si vous avez un problème de performance qui peut être résolu en modifiant la manière dont vous effectuez les itérations, vous n’avez pas vraiment de problème de performance. Vous avez un BUG, ​​parce que quelqu’un a écrit soit un iterator vraiment merdique, soit un indexeur vraiment nul.

Vous pourriez regarder la fonction for_each de la STL. Je ne sais pas si ce sera plus rapide que les deux options que vous présentez, mais il est plus standardisé que le for Qt et évite certains des problèmes que vous pourriez rencontrer avec une boucle régulière (à savoir l’indexation et les difficultés hors limites). avec la traduction de la boucle en une structure de données différente).