Parcourir un vecteur

Parcourir un vecteur - C++ - Programmation

Marsh Posté le 20-05-2005 à 18:10:15    

Bonjour,
 
J'ai trouvé 2 façons de parcourir un vecteur:
 
for(vector<wxString>::iterator i = vect.begin(); i != vect.end();++i){...}
for(int unsigned i=0;i<vect.size();i++){...}
 
Quel façon est la meilleur et pourquoi ? merci...

Reply

Marsh Posté le 20-05-2005 à 18:10:15   

Reply

Marsh Posté le 20-05-2005 à 18:35:38    

for(vector<wxString>::size_type i=0;i<vect.size();i++){...}
 
la meilleur ? sur quel critère ?

Reply

Marsh Posté le 20-05-2005 à 18:44:49    

Sur la vitesse à la quel le vecteur va être affiché...
 
Quel sera le code le plus rapide et pourquoi ?:
for(vector<wxString>::iterator i = vect.begin(); i != vect.end();++i){cout<<*i;}
for(int unsigned i=0;i<vect.size();i++){cout<<vect[i];}

Reply

Marsh Posté le 20-05-2005 à 18:57:08    

fait le test avec un grand vector<int> et un traitement minimale dans la boucle. Moi je dirais que ca se vaut, mais meme si avec  iterator c'est plus rapide ce n'est pas la le but ??
http://www.mindspring.com/~mgrand/ [...] m#Iterator

Reply

Marsh Posté le 20-05-2005 à 21:46:54    

Y'en a un qui marche pour vector, un autre pour à peu près tous les conteneurs.
J'avais fait le test, le 2° était un peu plus rapide. Ca me parrait plutôt normal, mais à priori on peut pas généraliser pour tous les compilos / STL. Et puis c'est pas vraiment là que tu vas voir la différence. Ca devrait pas être ton critère n°1 de choix. J'utilise plus souvent le 2 pour les vector, car c'est plus court à écrire.


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 20-05-2005 à 23:19:52    

Je viens de faire le test et en fait, j'ai à peu près le même résultat pour les deux (g++ 4.0.0 sous windows).
 
Donc je choisirai le 1er qui a le mérite de pouvoir être facilement remplacé par un autre conteneur.

Reply

Marsh Posté le 21-05-2005 à 07:46:44    

Franchement, je suis étonné que le 2 soit plus rapide, je m'attendrais à un résultat à peu de choses près identique, pour peu qu'on se donne la peine de déclarer l'itérateur correctement (et que l'implémentation de la STL soit optimisée). De toute façon, la 2e écriture n'est acceptable que pour les vecteurs. Pour les autres conteneurs, c'est jouer avec le feu.

Reply

Marsh Posté le 21-05-2005 à 10:53:40    

Bon j'ai fait le test avec VC++ 2003 :
le 1er est clairement plus rapide.
 
Et voici les différents temps obtenus :
 
1er : for(vector<int>::iterator i = vect.begin(); i != vect.end();++i){*i = 1;}  
avec optimisation :
g++ 4.0.0 : 3 secondes
VC++ 2003 : 3 secondes
sans optimisations :
g++ 4.0.0 : 14 secondes
VC++ 2003 : 21,1 secondes
 
2e : for(vector<int>::size_type i=0;i<vect.size();i++){vect[i] = 1;}  
avec optimisation :
g++ 4.0.0 : 3 secondes
VC++ 2003 : 3 secondes
sans optimisations :
g++ 4.0.0 : 33,7 secondes
VC++ 2003 : 24,7 secondes


Message édité par Tarabiscote le 22-05-2005 à 17:31:03
Reply

Marsh Posté le 21-05-2005 à 10:57:44    

Tarabiscote a écrit :


2e : for(int unsigned i=0;i<vect.size();i++){...}  


 
for(vector<wxString>::size_type i=0;i<vect.size();i++){...}
réitere plusieurs fois le test avec gcc pour avoir un temps plus precis


Message édité par skelter le 21-05-2005 à 10:58:49
Reply

Marsh Posté le 21-05-2005 à 11:11:53    

J'avais fait un copier coller dans mon message mais en fait c'était des int, je fais une affectation en plus, etc ...
 
Bon j'ai édité, sinon je suis désolé mais je l'ai lancé dans les 50 fois pour g++ et 2-3 fois pour VC++ 2003 à cause du temps qu'il met, mais le résultat est toujours le même.
 
PS : J'ai refais les tests en enlevant toutes les optimisations, je le rajoute avec les autres tests.


Message édité par Tarabiscote le 21-05-2005 à 11:45:06
Reply

Marsh Posté le 21-05-2005 à 11:11:53   

Reply

Marsh Posté le 21-05-2005 à 11:46:48    

tu fais exactement les meme tests avec g++ et vs2003 ? si c'est le cas la difference est trop importante, tu devrais regarder la sortie asm de g++ avec optimisation pour voir ce qu'il fait réelement

Reply

Marsh Posté le 21-05-2005 à 12:05:57    

J'affecte toujours des valeurs différentes et je fais afficher à la fin, je vois mal comment il ferait pour enlever des parties de codes si c'est ce que tu veux dire, sinon le code asm à l'air correct.
De plus si je double la boucle le temps est bien doublé.
 
PS : C'est exactement le même programme pour tous les tests.


Message édité par Tarabiscote le 21-05-2005 à 12:06:58
Reply

Marsh Posté le 21-05-2005 à 12:13:49    

alors comment ca pourrais etre 24 secondes avec vs et 3 secondes avec g++, c'est bien la meme machine ?

Reply

Marsh Posté le 21-05-2005 à 13:10:06    

Ben g++ optimise bien :D  
 
Tu peux faire des tests toi aussi, si t'as d'autres résultats...
Sinon on peut dire que, d'après mes résultats, le 1er est mieux (plus rapide, marche avec tous type de conteneurs), sauf avec les optimisations de g++ 4.0.0, dans ce cas les deux se valent (pour la vitesse).
 
PS : Oui, c'est bien la même machine.


Message édité par Tarabiscote le 21-05-2005 à 13:12:22
Reply

Marsh Posté le 21-05-2005 à 13:30:23    

mais ca donne quoi le code asm de la boucle comparer à vs2003 ?

Reply

Marsh Posté le 21-05-2005 à 14:42:34    

Euh... A tout hasard, t'as laissé le mode debug de VS, fait toutes les contres-optimisation possibles pour lancer le troll nmake vs gcc 4 ?

Reply

Marsh Posté le 21-05-2005 à 14:46:58    

IrmatDen a écrit :

Euh... A tout hasard, t'as laissé le mode debug de VS, fait toutes les contres-optimisation possibles pour lancer le troll nmake vs gcc 4 ?


C'est clair, j'allais dire la même chose :D


---------------
Friedrich Nietzsche : Le christianisme et l'alcool, les deux plus grands agents de corruption
Reply

Marsh Posté le 21-05-2005 à 14:58:43    

suffit de regarder l'assembleur ... la version avec iterator est un peu plus courte. Mais dans les 2 cas, la boucle principale est composée de 4 instructions sur ma machine. Donc les performances doivent être voisines

Reply

Marsh Posté le 21-05-2005 à 16:03:24    

Taz a écrit :

suffit de regarder l'assembleur ... la version avec iterator est un peu plus courte. Mais dans les 2 cas, la boucle principale est composée de 4 instructions sur ma machine. Donc les performances doivent être voisines


 
Avec Visual Studio 2003, sur un exemple "real-life" en release  multithreadé, on a ça qui est exécuté à chaque tour de boucle.


; for (size_t i=0; i<albums.size(); ++i)
mov  esi,dword ptr [esp+20h] ; i
mov  ecx,dword ptr [esi+4]  ; albums.begin()
test ecx,ecx ; albums.begin()==0  -> exit
je   FIN_DE_BOUCLE
mov  eax,dword ptr [esi+8] ; albums.end()
sub  eax,ecx  
sar  eax,2 ; sizeof(albums::value_type)
cmp  ebx,eax  
jae  FIN_DE_BOUCLE


(les commentaires correspondent à ma compréhension du truc).
En gros, il teste si albums.begin() vaut NUL, et il compare ensuite la variable i (qui est sur la pile) à (end()-begin()/sizeof(void *)).
 
Bref, c'est pas dément. Mais d'un autre côté, l'aliasing est un gros problème des applis multi-threadées et VC++ est plutôt conservateur sur cet aspect là. Donc il est "obligé" de vérifier que le contenu du vecteur n'a pas été modifé entre-temps.  
 
Je vais pas tarder à m'installer VC++2005 qui reconnait le mot __restrict (comme g++ 3.X d'ailleurs). On verra bien si ça permet de faire une différence. En attendant, il vaut mieux sortir le size() de la boucle car l'optimiseur ne le fait pas lui-même.

Reply

Marsh Posté le 21-05-2005 à 17:44:42    

VS ne le fait pas lui même !

Reply

Marsh Posté le 21-05-2005 à 18:11:02    

bref, je conclue : pour un parcours, iterator est vraiment meilleur parce que gcc (ça s'applique sans doute à d'autres compilateurs) incrémente son compteur de boucle 4 à 4 (la taille d'un int sur mon système), là ou a version size() fait un décalage de 2 (multplication par 4) après chaque incrémentation (étape inutile). Le code généré fait cependant la même taille.
 
Là où ça se complique, c'est lors d'un recopie
 

Code :
  1. void copy1(Vector &dst, const Vector &src)
  2.   {
  3.     Vector::iterator i = dst.begin();
  4.     Vector::const_iterator j = src.begin();
  5.     while(j != src.end())
  6.       {
  7.         *i++ = *j++;
  8.       }
  9.   }
  10.   void copy2(Vector &dst, const Vector &src)
  11.   {
  12.     for(Vector::size_type i = 0; i < src.size(); ++i)
  13.       {
  14.         dst[i] = src[i];
  15.       }
  16.   }


 
ici la version avec size() est nettement meilleur car, comme en C++, gcc produit un code qui n'utilise qu'une seul compteur, i. la version iterator est elle plus longue de 3 instructions car elle maintient 2 variable de boucle correspondant aux deux iterator.

Reply

Marsh Posté le 21-05-2005 à 18:23:36    

fait gaffe au variable 3 et 4 dans le décallage de la dimension hexagonale tridimensionnelle.... t'embete aps installe acdsee version 7 je pense.

Reply

Marsh Posté le 21-05-2005 à 18:30:56    

Hmmm, c'est là où on en vient à aimer le contrôle parental d'internet :/


---------------
Friedrich Nietzsche : Le christianisme et l'alcool, les deux plus grands agents de corruption
Reply

Marsh Posté le 21-05-2005 à 18:36:04    

Oups excuse moi je me suis trompé de topic..
 
Dans ton cas, utilise plutôt néro ;) . et sinon fait un croisement des variables c et d du commun de la racine exponentielle du degé de la coupe de la varible du numéro du loto

Reply

Marsh Posté le 21-05-2005 à 18:40:00    

Reply

Marsh Posté le 21-05-2005 à 22:44:04    

Désolé je voulais juste montrer que le 1er code n’est pas pire que le 2e.
Après je ne dis pas que dans certains cas avec certaines optimisations et certains compilateurs le 2e ne se comporte pas mieux.
 
En tout cas je ne voulais pas relancer la guerre entre VC et gcc.
 
J'utilise pas nmake, j'ai utilisé ça comme option (j'utilise pas trop VC++ donc y a sans doute mieux) : /D "NDEBUG" /G7 /arch:SSE2 /link /OPT:NOWIN98
 
Sinon j'ai même pas mis toutes les options de g++ ...
Enfin l'avantage de VC++ ça reste la taille de l'exe (88ko contre 533ko).

Reply

Marsh Posté le 21-05-2005 à 22:46:07    

n'importe quoi ... c'est pas parce que tu sais pas te servir de g++ qu'il faut tirer des conclusions hatives

Reply

Marsh Posté le 21-05-2005 à 22:49:43    

Quelles conclusions hâtives ?
 
Je suis le seul a avoir un temps sois peu montré des résultats, j'ai jamais empêcher personne de poster d'autres résultats et d'en tirer d'autres conclusions.
 
Alors j'espèrerai un peu plus de bonne fois.

Reply

Marsh Posté le 21-05-2005 à 23:19:02    

Tarabiscote a écrit :


Enfin l'avantage de VC++ ça reste la taille de l'exe (88ko contre 533ko).


ça par exemple.

Reply

Marsh Posté le 21-05-2005 à 23:22:12    

Sans doute parce qu'il oublie de préciser qu'il faut 15 meg de DLL pour que ça tourne :D


---------------
Friedrich Nietzsche : Le christianisme et l'alcool, les deux plus grands agents de corruption
Reply

Marsh Posté le 21-05-2005 à 23:32:07    

Friday Monday a écrit :

Sans doute parce qu'il oublie de préciser qu'il faut 15 meg de DLL pour que ça tourne :D


 
Mouais enfin
VC++ 2003 : kernel32.dll
gcc 4.0.0 : kernel32.dll plus msvcrt.dll
 
C'est pas vraiment ce que j'appele 15mo de plus ...
En tout cas c'est pas en faveur de gcc tout ça ...

Reply

Marsh Posté le 21-05-2005 à 23:39:38    

je comprends rien à vos histoires : la taille du binaire gcc ou VS est grosso modo là même

Reply

Marsh Posté le 21-05-2005 à 23:45:45    

Non car moi je compile pour mingw32, si tu compiles pour cygwin ou linux, dans ce cas là peut-être.
Mais quand on est sous windows c'est quand même mieux de ne pas avoir à passer par cygwin, enfin moi je préfère mais ce n’est qu’une question de goût.

Reply

Marsh Posté le 21-05-2005 à 23:58:21    

si tu compiles correctement avec mingw, tu obtiens une taille de binaire comme VS.

Reply

Marsh Posté le 22-05-2005 à 01:39:32    

Tarabiscote a écrit :

J'utilise pas nmake, j'ai utilisé ça comme option (j'utilise pas trop VC++ donc y a sans doute mieux) : /D "NDEBUG" /G7 /arch:SSE2 /link /OPT:NOWIN98


Et avec "/O2" (opt. for speed) ou "/O1" (opt. for size), ça donne quoi ?


Message édité par Lam's le 22-05-2005 à 01:40:00
Reply

Marsh Posté le 22-05-2005 à 09:34:38    

Ah ben voilà, je suis bête j'avais oublié de mettre /O2. (j'avais mis /03 comme sur gcc mais ça faisait rien alors je l'avais enlevé mais en fait c'était /02 :sweat: )
Donc c'est bon on a bien 3 secondes pareil :)
 
PS : Taz, ça m'intéresserai bien de savoir comment tu fais pour la taille.
 
Edit : Revenons au sujet voici la différence entre les deux :
 
1er

L65:
 movl $1, (%eax)
 addl $4, %eax
 cmpl %eax, %edx
 jne L65


2e

L37:
 movl $1, (%ecx,%edx,4)
 incl %edx
 cmpl %eax, %edx
 jb L37


Donc avec optimisation, je ne vois pas de différence du moins dans la boucle (y a plus qu’a vérifier le nombre de cycles par instructions pour être vraiment complet).
Je vais essayé de regarder un peu l'initialisation aussi mais la différence est négligeable (s'il y en a une).


Message édité par Tarabiscote le 22-05-2005 à 11:23:16
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed