Syndication : Atom 1.0  RSS 2.0
Blogs des développeurs   »   In-Depth Code

Article complet: Pre/Postincrementation : Fight !

05/11/2009

Permalink 15:49:18, Catégories: Récapitulatif C++, Code Poilu, 785 mots   French (FR) , DigitalGuru

[C++] Pre/Postincrementation : Fight !

Introduction

Au long de vos divagations programmistiques vous avez certainement dû apercevoir du code qui resemblait à ça :
for(int i = 0; i < 1000; ++i);

Mais quelle est donc la différence entre i++ et ++i? C’est ce que nous allons essayer de décrouvrir au long de cet article avec un petit bonus final...

[Suite:]

Une version PDF de mon article est disponible ici si vous le souhaitez. (Petit soucie de provider, le PDF sera dispo directement la semaine prochaine...)

Une question d’objet temporaire

Tout d’abord, il faut considérer ces incrémentations dans la cadre d’une expression composée. Par exemple :

int tableau[50]; 
int i = 0; // Cas 1.  
tableau[i++] = 0;  
 
i = 0; // Cas 2. 
tableau[++i] = 0;

Quelle est la différence entre ++i et i++ ?

* i++ : Appelée post-incrémentation, l’expression envoie la valeur de i à la fonction, puis incrémente sa valeur de 1. Dans le cadre de notre exemple :
- tableau[0] vaudra 0.
- i vaudra 1 après l’affectation.

* ++i : Appelée pré-incrementation, l’expression incrémente de 1 la valeur de i puis envoie sa nouvelle valeur à la fonction. Dans notre exemple:
- tableau[1] vaudra 0.
- i vaudra 1.

Il y a donc une différence énorme de signification dans les deux écritures et il faudra faire attention au comportement de notre porgramme lorsqu’on manie ce genre d’expressions.
Quel est la différence entre ++i et i++ dans une expression simple ?

Dans un code du type :

int i = 0; 
++i; // i = i + 1; 
i++; // i = i + 1;

Les deux expressions ont exactement le même comportement et ne font qu’incrémenter la valeur de i de 1.

Pourquoi vaut-il mieux utiliser la pré-incrémentation que la post-incrémentation ?

C’est simplement une question de rapidité. En effet, la post-incrémentation va créer une variable temporaire pour s’exécuter ce que ne fera pas le pré-incrémentation. Qui dit variable temporaire, dit accès mémoire et donc perte de temps et de place.
Voici les équivalences :

int i = 0; 
tableau[i++] = 0; 
 
// Equivaut a : 
 
int i = 0; 
int tmpi = i; // Une variable temporaire est cree. 
tableau[tmpi] = 0; 
i++; 

et

int i = 0; 
tableau[++i] = 0; 
 
// Equivaut a :  
 
int i = 0; 
i = i + 1; 
tableau[i] = 0;

Tout ça pour ça ?

Une variable temporaire, c’est pas grande chose, mais rappelez vous de la boucle for : l’incrémentation est appelée à chaque itération ce qui, à terme peut ralentir l’exécution du programme.
Il faut tout de même savoir que la plupart du temps, le compilateur optimisera. Il y a cependant des cas o`u le compilateur ne saura pas si pré-incrémenter ne changera pas le comportement et ne fera donc rien alors qu’une optimisation aurait dûe être faite.
Comme précisé par Matthieu Brucher, le compilateur aura surtout du mal à optimiser dans le cas d'objets plus complexes et notamment des itérateurs (Cf STL).
D'après les tests effectué d'après l'observation de spiceguid, la pré-décrémentation est plus lente (encore que...) que la pré-incrémentation :
time ./TestDecrementation && time ./TestIncrementation  
 
real  0m3.600s 
user  0m3.590s 
sys  0m0.000s 
 
real  0m3.550s 
user  0m3.440s 
sys  0m0.000s 

avec un code du type :

for(int i = 1000000000; i >= 0; --i); 
// Et 
for(int i = 0; i < 1000000000; ++i);

Vous êtes prévenus maintenant !

Bonus : Surchage des opérateurs

Vous êtes vous déjà demandé comment faire la différence entre une post-opération et une pré-opération lorsqu’il faut surcharger l’opérateur unaire d’incrémentation (++ ou - -) ? Parce qu’à priori, le code est du genre :

inline operator ++() { // Post ou pre-incrementation ??  
  // Code ... 3  
}

Il y a une astuce ! En effet, pour surcharger une post-opération, il faut ajouter un paramètre inutile ! D’o‘u :

inline operator ++() { // Pre-incrementation 
  // Code ... 
}  
 
inline operator ++(int) { // Post-incrémentation 
  // Code ... 

Conclusion

J’espère que ce premier article vous a plu et qu’il vous incitera à revenir régulièrement !

Références

C++ Cookbook
By Jeff Cogswell, Christopher Diggins, Ryan Stephens, Jonathan Turkanis
Publisher: O’Reilly
Pub Date: November 2005
ISBN: 0-596-00761-2

C++ Coding Standards: 101 Rules, Guidelines, and Best Practices
By Herb Sutter, Andrei Alexandrescu
Publisher: Addison Wesley Professional
Pub Date: October 25, 2004
ISBN: 0-321-11358-6

Et surêment plein d’autres...

Merci à Jey et à Paulo pour la relecture.\\
Merci aussi à Matthieu Brucher et spiceguid pour leurs observations très contructives.

Social Bookmarking:

                                     

Adresse de trackback pour cet article:

http://blog.developpez.com/htsrv/trackback.php?tb_id=8281

Commentaires, Trackbacks, Pingbacks:

Connectez-vous pour vous abonner à cet article:

Flux de commentaires pour cet article : Atom 1.0  RSS 2.0
Commentaire de: Matthieu Brucher [Membre] · http://matthieu-brucher.developpez.com/
En fait, pour des variables entières, le compilateur sait très bien optimiser les boucles for. En revanche, pour les itérateurs, ce n'est pas du tout le cas. Donc l'intérêt de la préincrémentation est surtout visible lorsqu'on effectue des boucles sur des objets plus complexes que les entiers.
Permalien 06/11/2009 @ 09:48
Commentaire de: DigitalGuru [Membre]
Merci de la précision, j'ajoute ça à l'article !
Permalien 06/11/2009 @ 09:59
Commentaire de: SpiceGuid [Membre]
Avez-vous testé la décrémentation vs. l'incrémentation ?

for(int i = 1000; i >= 0; --i);

L'intérêt de la décrémentation c'est que la comparaison avec 0 est potentiellement plus rapide que la comparaison avec 1000.
Certains cpu (pas x86) ont d'ailleurs une instruction spécifique qui combine décrémentation et branchement conditionnel en une seule opération.



Permalien 06/11/2009 @ 15:45
Commentaire de: DigitalGuru [Membre]
Très bonne question ! Je ferais les tests en rentrant ce soir et j'updaterai l'article si nécessaire.
Permalien 06/11/2009 @ 16:31
Commentaire de: DigitalGuru [Membre]
Bien vu mais j'obtient des résultats du type :
real 0m3.696s
user 0m3.680s
sys 0m0.000s

real 0m3.501s
user 0m3.420s
sys 0m0.000s

Bien sur, je n'ai pas fait de tests poussé, mais les résultats on l'air au mieux similaire, si l'incrémentation n'est pas plus rapide que la décrémentation. Ce qui semble assez logique finalement puisque l'arithmetique signée utilise le complément à 2 pour faire une soustraction et donc à priori plus de cycle. Je ne peux cependant pas vous garantir ça.

Mais j'ajoute ça à l'article !
Merci de votre observation.

Permalien 06/11/2009 @ 17:08

Vous devez être identifié pour poster un commentaire.

Liste des blogs

In-Depth Code

Ce blog traite d'un aspect très spécifique au C++ : Le code poilu, i.e. l'art de faire du beau et souvent du compliqué. Des standards, aux erreurs à éviter, en passant par l'optimisation, j'essaierai au travers d'articles de quelques pages de faire partager les nouvelles techniques que j'apprend chaque jour ! On ne peux pas dire que mes articles sont des tutoriaux ou des cours, ils sont même plutôt adressés à des personnes ayant un certain niveau en programmation C++.

Pour un code plus poilu !

Catégories


Rechercher

<  Mars 2011  >
Lun Mar Mer Jeu Ven Sam Dim
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      

Syndiquez ce blog XML

Articles :

Commentaires :

 
 
 
 
Partenaires

Hébergement Web