55 votes

Boucle 'for' contre 'foreach' de Qt en C++.

Qu'est-ce qui est le mieux (ou le plus rapide), un C++ ? for ou la boucle foreach fourni par Qt ? Par exemple, la condition suivante

QList<QString> listofstrings;

Lequel est le meilleur ?

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

o

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

7 votes

Une remarque rapide : si vous ne prévoyez pas de modifier la variable de la boucle foreach, vous devriez utiliser une const QString& à la place - cela a également des implications sur la vitesse.

0 votes

Voici une explication de la raison pour laquelle vous devez faire attention à inclure la const : labs.qt.nokia.com/2009/01/23/iterating-efficiently

1 votes

Le complément important à cette question est que vous ne devez jamais utiliser Qt foreach pour les conteneurs non Qt, il est fort probable qu'une copie profonde sera effectuée et c'est ce que vous ne voulez pas, même sans le profiler au préalable.

153voto

paxdiablo Points 341644

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

Le grand nombre de questions posées sur StackOverflow pour savoir si telle ou telle méthode est plus rapide, 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 usted sont si vous êtes vraiment concerné, établissez votre propre profil et agissez en fonction de ce que vous trouvez.

Mais je pense que vous constaterez très probablement que cette question n'a d'importance que dans les travaux les plus intenses en matière de traitement des données. La différence pourrait bien n'être que de quelques secondes et encore, seulement lors du traitement d'un grand nombre d'éléments.

Faites fonctionner votre code primero . Puis le faire fonctionner rapide (et seulement si vous trouvez un réel problème de performance).

Le temps consacré à l'optimisation avant que vous n'ayez terminé la fonctionnalité et que vous puissiez établir un profil adéquat est une perte de temps.

51 votes

Ce numéro a dépassé le stade de la plaisanterie depuis longtemps. Nous devrions écrire un robot de réponse qui cherche "lequel est le plus rapide" et répond automatiquement : profilez-le

2 votes

Voir stackoverflow.com/questions/771092/ Nous allons voir s'il survit :-)

21 votes

Non pas que cela s'applique vraiment à l'exemple simple, mais ce que j'aime dire, c'est que "le code incorrect est aussi peu optimisé que possible".

25voto

Parker Points 1098

Tout d'abord, je voudrais juste dire que je suis d'accord avec Pax, et que la vitesse n'entre probablement pas en ligne de compte. foreach l'emporte haut la main sur la base de la lisibilité, et c'est suffisant dans 98% des cas.

Mais bien sûr, les gars de Qt se sont penchés sur la question et ont réalisé un profilage : http://blog.qt.io/blog/2009/01/23/iterating-efficiently/

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

19voto

Evan Teran Points 42370

Cela n'a vraiment pas d'importance. . Il est probable que si votre programme est lent, ce n'est pas le problème. Cependant, il faut noter que vous ne faites pas une comparaison complètement égale. Qt foreach est plus similaire à ceci (cet exemple utilisera QList<QString> ) :

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

La macro est en mesure de le faire en utilisant certaines extensions du compilateur (comme l'extension de GCC __typeof__ ) pour obtenir le type du conteneur passé. Imaginez également que la fonction BOOST_FOREACH est un concept 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 d'itérer réellement. Si vous utilisez un type dont l'allocation n'est pas contiguë (je soupçonne que c'est le cas avec le type QList<> ), l'indexation sera plus coûteuse car le code doit calculer "où" se trouve le n-ième élément.

Ceci étant dit. C'est toujours n'a pas d'importance. La différence de temps entre ces deux morceaux de code sera négligeable, voire inexistante. Ne perdez pas votre temps à vous en inquiéter. Écrivez ce qui vous semble le plus clair et le plus compréhensible.

EDITAR: En prime, actuellement, je favorise fortement la version C++11 de l'itération des conteneurs, elle est propre, concise et simple :

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

0 votes

Votre déclaration concernant at() vs operator[] Les performances ne sont pas correctes pour Qt. Tous deux effectuent ou non la vérification des limites en fonction des options de compilation. Les exceptions ne sont pas utilisées dans Qt. En revanche, le documentation dit " at() peut être plus rapide que operator[]() car elle ne provoque jamais de copie profonde."

16voto

ymoreau Points 1404

Desde Qt 5.7 le site foreach est dépréciée, Qt vous encourage à utiliser la macro C++11 for à la 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/ )

0 votes

Veuillez également ajouter ce message en commentaire de la question, car davantage de personnes doivent le voir !

13voto

Je ne veux pas répondre à la question de savoir lequel est le plus rapide, mais je veux dire lequel est le meilleur.

Le plus gros problème avec le foreach 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 parce que les classes de Qt sont recomptées", mais comme une copie est utilisée, vous ne modifiez pas du tout votre conteneur d'origine.

En résumé, le foreach de Qt ne peut être utilisé que pour des boucles en lecture seule et doit donc être évité. Qt vous laissera volontiers écrire une boucle foreach dont vous pensez qu'elle mettra à jour/modifiera votre conteneur, mais à la fin, tous les changements sont rejetés.

0 votes

Je suis d'accord. Je suis tombé sur un foreach pendant le profilage : Il s'est avéré que j'avais changé un QList à un QVarLengthArray (encore une fois après le profilage) et a trouvé le foreach en copiant mon QVarLengthArray . Oups. Je suis allé pour un régulier for et cette trace de pile n'apparaissait plus dans le profileur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X