Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Un doute existenciel a propos du parcours de liste dans une boucle 'for'

79 réponses
Avatar
meow
> for ( iterator it=3Dliste.begin() ; it!=3Dliste.end() ; ++it )

Question =E0 deux balles : A tous les coups, le compilo n'a aucun moyen
d'extraire la valeur de liste.end() une fois pour toute avant le d=E9but
de la boucle, du coup =E0 chaque it=E9ration de la boucle le programme se
retape l'appel =E0 liste.end() !
La question toute simple que je me pose est donc : est-ce que c'est pas
mieux de faire

> iterator end=3Dliste.end()
> for ( iterator it=3Dliste.begin() ; it!=3Dend ; ++it )

10 réponses

1 2 3 4 5
Avatar
Alain Gaillard


Tu l'as mesuré ?



Très honnêtement ? Jamais :-)

Dans l'ensemble, je crois qu'on peut dire que déclarer une
variable uniquement pour lire end() qu'une fois est une
optimisation prémature,


Ben moi je ne trouve pas. Pour moi une optimisation prématurée c'est
quand on introduit un risque d'erreur ou qu'on complique le code dans
l'optique d'un gain de performance alors qu'on ferait mieux d'abord de
se concentrer à écrire un code qui marche :). Dans notre cas ,pas de
complication. Et pas de risque d'erreur non plus. (Etant entendu qu'on
sait bien que l'itérateur peut se trouver invalidé)

J'ai retouvé le gotw, c'est le 2 (http://www.gotw.ca/gotw/002.htm)

Herb Sutter ne s'étend pas trop, il dit simplement:
"There are other optimisation opportunities, such as avoiding the
redundant calls to end()."
Par contre dans son bouquin Exceptional C++, il insiste un peu plus
dessus. Je me range à son avis. Je trouve que c'est une bonne habitude
d'écriture sans danger.

--
Alain

Avatar
Alain Gaillard


Ou non. Un bon optimisateur peut faire beaucoup.


Oui, ça c'est certain. D'ailleurs quand j'aurais un peu de temps
j'essaierai de regarder ça plus en détail.


Une déclaration en plus. Une variable en plus. Pour rien.


Une variable de plus certes, mais en quoi elle te gêne ?


Non, merci.


LOL

--
Alain

Avatar
kanze
Alain Gaillard wrote:

Tu l'as mesuré ?


Très honnêtement ? Jamais :-)


Moi, en fait, oui. Suite au gotw de Herb, j'ai fait un petit
bench, pour comparer les ++ i et les i ++ ; à l'occasion, j'ai
essayé aussi avec l'appel de container.end() dans la boucle, et
une fois seulement en tête de la boucle. Les résultats étaient
intéressants, même s'ils ne valent que pour l'environement testé
(g++ sous Solaris, sur Sparc -- et je crois que c'était encore
g++ 2.95.2).

Je n'ai trouvé de différence entre ++ i et i ++ avec aucun des
itérateurs standard (y compris les reverse_iterator). Extraire
l'appel de container.end() de la boucle faisait bien une
différence, mais somme tout assez petite. Il ne faut vraiment
rien faire dans la boucle pour que ça se mesure dans un
programme réel.

Dans l'ensemble, je crois qu'on peut dire que déclarer une
variable uniquement pour lire end() qu'une fois est une
optimisation prémature,


Ben moi je ne trouve pas. Pour moi une optimisation prématurée
c'est quand on introduit un risque d'erreur


Tout code supplémentaire introduit un risque d'erreur.

ou qu'on complique le code


Par exemple, en introduisant une variable supplémentaire ?

dans l'optique d'un gain de performance alors qu'on ferait
mieux d'abord de se concentrer à écrire un code qui marche :).
Dans notre cas ,pas de complication. Et pas de risque d'erreur
non plus. (Etant entendu qu'on sait bien que l'itérateur peut
se trouver invalidé)


Dans les deux cas, en ce qui concerne ce qu'il y a dans les
parenthèses. En revanche, je ne vois pas comment te peux dire
qu'introduire une variable supplémentaire n'augmente pas la
complexité, ni la risque d'erreur.

J'ai retouvé le gotw, c'est le 2 (http://www.gotw.ca/gotw/002.htm)

Herb Sutter ne s'étend pas trop, il dit simplement:
"There are other optimisation opportunities, such as avoiding the
redundant calls to end()."


Ce qui n'était pas dans l'original, d'ailleurs. Il l'a ajouté à
la suite de mes mesures.

Par contre dans son bouquin Exceptional C++, il insiste un peu
plus dessus. Je me range à son avis. Je trouve que c'est une
bonne habitude d'écriture sans danger.


Moi non. C'est un point où je ne suis pas d'accord avec lui. Je
trouve qu'il s'inquiète bien trop de la performance, trop tôt.
Je préfère toujours le code plus facile à maintenir. Ce qui veut
dire, sans variables supplémentaires. Et sans s'écarter d'une
pratique existante déjà établi, si c'est le cas pour le i++.

Et je constate par expérience que mon code est plus qu'assez
vite.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
Alain Gaillard


Je n'ai trouvé de différence entre ++ i et i ++ avec aucun des
itérateurs standard (y compris les reverse_iterator). Extraire
l'appel de container.end() de la boucle faisait bien une
différence, mais somme tout assez petite.


Ca ne m'étonne pas. Là je suis en train d'essayer de voir si VC 8.0 est
capable de supprimer l'objet temporaire. Et sous réserve de toutes
erreur de ma part avec les options de compilation, le compilo ne
supprime pas la construction de l'objet temporaire

Il ne faut vraiment
rien faire dans la boucle pour que ça se mesure dans un
programme réel.


Oui ça c'est un argument.

Tout code supplémentaire introduit un risque d'erreur.


Du code oui. Mais là il s'agit juste d'une variable au sujet de laquelle
personne ne se méprendra.

Dans les deux cas, en ce qui concerne ce qu'il y a dans les
parenthèses. En revanche, je ne vois pas comment te peux dire
qu'introduire une variable supplémentaire n'augmente pas la
complexité, ni la risque d'erreur.


Franchement dans ce cas, je ne vois pas bien le problème potentiel.

Ce qui n'était pas dans l'original, d'ailleurs. Il l'a ajouté à
la suite de mes mesures.


Donc il a conclu que le coût de la construction de l'itérateur n'est pas
négligeable mesures en main.

Moi non. C'est un point où je ne suis pas d'accord avec lui.


C'est tout l'univers de C++ ça la diversité ;)
Moi c'est quand il dit que le test d'auto-affectation ne devrait pas
être nécessaire pour un operator= que je ne partage pas son avis.

Je
trouve qu'il s'inquiète bien trop de la performance, trop tôt.


C'est vrai que c'est un travers dans lequel il ne faut pas tomber. Là je
suis bien d'accord avec toi. C'est juste qu'à mon avis à la variable
supplémentaire pour end(), ce n'est pas porteur de problèmes potentiels.
enfin AMHA.

Je préfère toujours le code plus facile à maintenir. Ce qui veut
dire, sans variables supplémentaires.


D'accord, mais dans notre cas toujours, je ne vois pas bien le problème
de maintenance.

Et je constate par expérience que mon code est plus qu'assez
vite.


Je dois aussi confesser que pour mon malheur je fait beaucoup de Java et
c'est en codant des boucles sur des tableaux en Java que j'ais pris
l'habitude de sortir tableau.length de la boucle. Et je me suis mis à
faire l'équivalent en C++

--
Alain

Avatar
Fabien LE LEZ
On Fri, 22 Sep 2006 13:17:45 +0200, Alain Gaillard
:

Une déclaration en plus. Une variable en plus. Pour rien.


Une variable de plus certes, mais en quoi elle te gêne ?


Ça rend le programme encore plus compliqué à lire et à maintenir.


Avatar
Fabien LE LEZ
On Fri, 22 Sep 2006 13:59:54 +0200, Alain Gaillard
:

Moi c'est quand il dit que le test d'auto-affectation ne devrait pas
être nécessaire pour un operator= que je ne partage pas son avis.


Tiens ? Tu as un contre-exemple ?

(À part bien sûr les problèmes d'optimisation, où ce test peut
effectivement servir.)

Avatar
Sylvain Togni
Alain Gaillard wrote:, :

Je n'ai trouvé de différence entre ++ i et i ++ avec aucun des
itérateurs standard (y compris les reverse_iterator). Extraire
l'appel de container.end() de la boucle faisait bien une
différence, mais somme tout assez petite.


Ca ne m'étonne pas. Là je suis en train d'essayer de voir si VC 8.0 est
capable de supprimer l'objet temporaire. Et sous réserve de toutes
erreur de ma part avec les options de compilation, le compilo ne
supprime pas la construction de l'objet temporaire


Je viens de faire un rapide test avec VC 6.0, il génère
exactement le même code assembleur pour une boucle avec
"it != container.end()" ou avec "it != end", et ce avec
std::vector, std::list et std::deque mais pas avec
std::set ni std::map.

Et entre ++i et i++, aucune différence dans le code généré,
quelque soit le container.

--
Sylvain Togni


Avatar
loufoque

Je viens de faire un rapide test avec VC 6.0


Tu ferais mieux de faire tes tests avec un vrai compilateur C++ par contre.

Avatar
Alain Gaillard


Je viens de faire un rapide test avec VC 6.0, il génère
exactement le même code assembleur pour une boucle avec
"it != container.end()" ou avec "it != end", et ce avec
std::vector, std::list et std::deque mais pas avec
std::set ni std::map.


Voilà une info intéressante.


--
Alain

Avatar
Alain Gaillard

Tiens ? Tu as un contre-exemple ?


Que veux tu dire par contre exemple ?
Si j'écris une classe qui définit l'opérator =, l'auto-affectation je la
teste systématiquement. Se contenter de retourner *this au lieu
d'exécuter plein de code me paraît tellement naturel.

--
Alain

1 2 3 4 5