Accueil > > > PERFORMANCE : I++ OU ++I ?
PERFORMANCE : I++ OU ++I ?
Information sur la source
Description
Bien sûr, il y a parfois des raisons pour choisir i++ plutôt que ++i mais vous êtes vous posé la question de la performance ? Surtout lorsque l'on utilise cette construction à répétition ... dans une boucle par exemple. Alors : votez vous pour i++ (comme la majorité des développeurs), pour ++i (la minorité) ou pensez vous que c'est équivalent (ne sait pas) ? Voyons cela de l'intérieur : à l'occasion de la surcharge des opérateurs ++
Source
- /*
- On vous donne la classe A suivante :
- class A
- {
- private: int i_;
- public:
- A(int i) : i_(i){}
- void print() const {cout << "valeur A=" << i_ << endl;}
- };
- On vous demande de supporter le "Use Case" suivant :
-
- int main(){
- A a(0);
- a++.print();
- (++a).print();
- }
-
- 0) Question préliminaire :
- ---------------------------
- Quelle est l'arité de ++ dans a++ ? et dans ++a ?
- (l'arité d'un opérateur est son nombre de paramètres)
- la réponse dans les deux cas devrait être UN
- Donc, en l'implémentant comme méthode de la classe A, et en tenant compte
- du paramètre caché 'this', elle ne doit avoir aucun paramètre
- Comment différencier alors le cas a++ du cas ++a ?
- Les standards répondent à ce problème en imposant un paramètre 'int'
- à la version postfixée
-
- I) Commençons par le premier opérateur :
- -----------------------------------------
- l'implémentation de la version postfixée de l'opérateur ++
- Quel est le prototype ?
- Ecrivons la version complète de l'opérateur (sa vision compilateur)
- a++ est équivalent à a.operator++(int)
- Que doit faire cet opérateur ?
- d'abord incrémenter 'a', ensuite renvoyer l'ancienne valeur de 'a'
- On remarquera qu'ici, il est "NECESSAIRE DE CREER UN OBJET TEMPORAIRE"
- voici notre implémentation comme méthode de la classe A:
- ?A? operator++(int)
- { A clone(*this); //ceci est un appel au Ctor de copie de A
- //permet de mémoriser l'ancienne valeur
- ++i_; //incrémente l'objet courant
- return clone; //renvoie l'ancienne valeur
- } // ici appel au "DTOR DE L'OBJET TEMPORAIRE"
-
-
- où ?A? représente soit 'A', 'const A', 'A&' ou 'const A&'
- On élimine les pointeurs car le résultat de a++ est forcément un espèce de A
- Comment choisir ?
- Eliminons les références car l'objet renvoyé est temporaire (créé sur la pile)
- il disparait dès la sortie du bloc '}', il est "NECESSAIRE DE RENVOYER UNE COPIE"
- J'espère maintenant que vous êtes dégoutés du POST-FIXE !
-
- Pour départager les ex-aequos (A et const A) voyons comment se comporte
- l'opérateur des types de base (l'int par exemple)
- Testons le code suivant :
- int i(0); i++++;
- Une erreur de compilation survient car l'opérateur ++ postfixé des 'int'
- attend une L-VALUE (Left-value).
- L-VALUE : variable possédant une zone de mémoire accessible en lecture/écriture
- donc en particulier, pas une variable temporaire, ni une const.
- En résumé, une variable pouvant être placée à gauche du signe =
- Ceci nous donne notre réponse :
- le type de retour DOIT être un 'const A' plutôt que 'A' pour être conforme au standards
-
- On peut alors tester le premier opérateur ainsi
- int main()
- {
- int i(0);
- //i++++; ne compile pas ++ requiert l-value
- A a(0);
- //a++++; // ne compile pas si operator++(int) retourne un const
- cout << "valeur i=" << i++ << endl;//renvoie 0
- cout << "valeur i=" << i << endl;//renvoie 1
- a++.print();//renvoie 0 : attention à bien prototyper la méthode print const
- a.print();//renvoie 1
-
- return 0;
- }
-
- II) Deuxième opérateur :
- -----------------------------------------
- Quel est le prototype de la version préfixée de l'opérateur ++ ?
- ++a est équivalent à a.operator++()
- Que doit faire cet opérateur ?
- d'abord incrémenter 'a', ensuite renvoyer la nouvelle valeur de 'a'
- On remarquera qu'ici, que l'on n'a pas besoin d'objet temporaire (COOL)
-
- voici notre implémentation comme méthode de la classe A:
- ?A? operator++()
- { ++i_; //incrémente l'objet courant
- return *this; //le renvoie
- }
- On peut renvoyer un 'A', 'const A', 'A&' ou 'const A&'
- Le meilleur pour les performances est de renvoyer par référence
- Voyons si elle doit être const ou non avec la même technique que précédemment
- on teste
- ++++i; ... et ça marche !
- On peut donc retourner un A& (et c'est préférable pour imiter les types de base)
-
- */
-
- #include <iostream.h>
- class A
- {
- private: int i_;
- public: A(int i) : i_(i){}
- void print() const {cout << "valeur A=" << i_ << endl;}
- const A operator++(int)
- { A clone(*this); //ceci est un appel au Ctor de copie de
- //permet de mémoriser l'ancienne valeur
- ++i_; //incrémente l'objet courant
- return clone; //renvoie l'ancienne valeur
- }
- A& operator++()
- { ++i_; //incrémente l'objet courant
- return *this; //le renvoie
- }
- };
-
- int main()
- {
- int i(0);
- //i++++; ne compile pas ++ requiert l-value
- A a(0);
- //a++++; // ne compile pas si operator++(int) retourne un const
-
- //test post fixé
- cout << "valeur i=" << i++ << endl;//renvoie 0
- cout << "valeur i=" << i << endl;//renvoie 1
- a++.print();//=> 0 : attention à bien prototyper la méthode print const
- a.print();//=> 1
-
- //test pré fixé
- cout << "valeur i=" << ++i << endl;//renvoie 2
- cout << "valeur i=" << i << endl;//renvoie 2
- (++a).print(); //=> 2 //parenthèses nécessaires (précédence de . sur ++)
- a.print(); //=> 2
- return 0;
- }
-
- /* "CONCLUSION":
- Faisons le bilan :
- en notation "POST-FIXE" :
- un Ctor pour l'objet temporaire (Ctor de Copie ou Ctor défaut+Affectation)
- l'incrémentation
- un Ctor de Copie pour le retour par valeur
- un Dtor de l'objet temporaire
-
- en notation "PRE-FIXE" :
- l'incrémentation
-
- Un dernier mot pour dire que les types de bases se comportent de la même
- manière que les classes (une temporaire), même si les dégâts sont moins flagrants
- "il n'y a pas de différence dans le cas d'int" (merci aux commentaires ci-dessous . le 04/11)
- Et si notre classe avait des données membres de type classe, et/ou des
- classes de bases ... le poids des Ctor/Dtors devient ENORME...
- */
-
/*
On vous donne la classe A suivante :
class A
{
private: int i_;
public:
A(int i) : i_(i){}
void print() const {cout << "valeur A=" << i_ << endl;}
};
On vous demande de supporter le "Use Case" suivant :
int main(){
A a(0);
a++.print();
(++a).print();
}
0) Question préliminaire :
---------------------------
Quelle est l'arité de ++ dans a++ ? et dans ++a ?
(l'arité d'un opérateur est son nombre de paramètres)
la réponse dans les deux cas devrait être UN
Donc, en l'implémentant comme méthode de la classe A, et en tenant compte
du paramètre caché 'this', elle ne doit avoir aucun paramètre
Comment différencier alors le cas a++ du cas ++a ?
Les standards répondent à ce problème en imposant un paramètre 'int'
à la version postfixée
I) Commençons par le premier opérateur :
-----------------------------------------
l'implémentation de la version postfixée de l'opérateur ++
Quel est le prototype ?
Ecrivons la version complète de l'opérateur (sa vision compilateur)
a++ est équivalent à a.operator++(int)
Que doit faire cet opérateur ?
d'abord incrémenter 'a', ensuite renvoyer l'ancienne valeur de 'a'
On remarquera qu'ici, il est "NECESSAIRE DE CREER UN OBJET TEMPORAIRE"
voici notre implémentation comme méthode de la classe A:
?A? operator++(int)
{ A clone(*this); //ceci est un appel au Ctor de copie de A
//permet de mémoriser l'ancienne valeur
++i_; //incrémente l'objet courant
return clone; //renvoie l'ancienne valeur
} // ici appel au "DTOR DE L'OBJET TEMPORAIRE"
où ?A? représente soit 'A', 'const A', 'A&' ou 'const A&'
On élimine les pointeurs car le résultat de a++ est forcément un espèce de A
Comment choisir ?
Eliminons les références car l'objet renvoyé est temporaire (créé sur la pile)
il disparait dès la sortie du bloc '}', il est "NECESSAIRE DE RENVOYER UNE COPIE"
J'espère maintenant que vous êtes dégoutés du POST-FIXE !
Pour départager les ex-aequos (A et const A) voyons comment se comporte
l'opérateur des types de base (l'int par exemple)
Testons le code suivant :
int i(0); i++++;
Une erreur de compilation survient car l'opérateur ++ postfixé des 'int'
attend une L-VALUE (Left-value).
L-VALUE : variable possédant une zone de mémoire accessible en lecture/écriture
donc en particulier, pas une variable temporaire, ni une const.
En résumé, une variable pouvant être placée à gauche du signe =
Ceci nous donne notre réponse :
le type de retour DOIT être un 'const A' plutôt que 'A' pour être conforme au standards
On peut alors tester le premier opérateur ainsi
int main()
{
int i(0);
//i++++; ne compile pas ++ requiert l-value
A a(0);
//a++++; // ne compile pas si operator++(int) retourne un const
cout << "valeur i=" << i++ << endl;//renvoie 0
cout << "valeur i=" << i << endl;//renvoie 1
a++.print();//renvoie 0 : attention à bien prototyper la méthode print const
a.print();//renvoie 1
return 0;
}
II) Deuxième opérateur :
-----------------------------------------
Quel est le prototype de la version préfixée de l'opérateur ++ ?
++a est équivalent à a.operator++()
Que doit faire cet opérateur ?
d'abord incrémenter 'a', ensuite renvoyer la nouvelle valeur de 'a'
On remarquera qu'ici, que l'on n'a pas besoin d'objet temporaire (COOL)
voici notre implémentation comme méthode de la classe A:
?A? operator++()
{ ++i_; //incrémente l'objet courant
return *this; //le renvoie
}
On peut renvoyer un 'A', 'const A', 'A&' ou 'const A&'
Le meilleur pour les performances est de renvoyer par référence
Voyons si elle doit être const ou non avec la même technique que précédemment
on teste
++++i; ... et ça marche !
On peut donc retourner un A& (et c'est préférable pour imiter les types de base)
*/
#include <iostream.h>
class A
{
private: int i_;
public: A(int i) : i_(i){}
void print() const {cout << "valeur A=" << i_ << endl;}
const A operator++(int)
{ A clone(*this); //ceci est un appel au Ctor de copie de
//permet de mémoriser l'ancienne valeur
++i_; //incrémente l'objet courant
return clone; //renvoie l'ancienne valeur
}
A& operator++()
{ ++i_; //incrémente l'objet courant
return *this; //le renvoie
}
};
int main()
{
int i(0);
//i++++; ne compile pas ++ requiert l-value
A a(0);
//a++++; // ne compile pas si operator++(int) retourne un const
//test post fixé
cout << "valeur i=" << i++ << endl;//renvoie 0
cout << "valeur i=" << i << endl;//renvoie 1
a++.print();//=> 0 : attention à bien prototyper la méthode print const
a.print();//=> 1
//test pré fixé
cout << "valeur i=" << ++i << endl;//renvoie 2
cout << "valeur i=" << i << endl;//renvoie 2
(++a).print(); //=> 2 //parenthèses nécessaires (précédence de . sur ++)
a.print(); //=> 2
return 0;
}
/* "CONCLUSION":
Faisons le bilan :
en notation "POST-FIXE" :
un Ctor pour l'objet temporaire (Ctor de Copie ou Ctor défaut+Affectation)
l'incrémentation
un Ctor de Copie pour le retour par valeur
un Dtor de l'objet temporaire
en notation "PRE-FIXE" :
l'incrémentation
Un dernier mot pour dire que les types de bases se comportent de la même
manière que les classes (une temporaire), même si les dégâts sont moins flagrants
"il n'y a pas de différence dans le cas d'int" (merci aux commentaires ci-dessous . le 04/11)
Et si notre classe avait des données membres de type classe, et/ou des
classes de bases ... le poids des Ctor/Dtors devient ENORME...
*/
Sources du même auteur
Sources de la même categorie
Commentaires et avis
|
Derniers Blogs
[TECHDAYS2012] OUI J'Y SERAI![TECHDAYS2012] OUI J'Y SERAI! par JeremyJeanson
Bonsoir, Certes, je l'annonce avec un peu de retard, mais je serai effectivement au Techdays demain. Comme l'an dernier, je participerai au programme ATE (Ask The Expert). Si vous avez des questions Workflow, WCF, AppFabric ou plus généralement .net, n'hé...
Cliquez pour lire la suite de l'article par JeremyJeanson TFS INTEGRATION TOOLS - SUIVI DES SYNCHRONISATIONS AVEC REPORTING SERVICESTFS INTEGRATION TOOLS - SUIVI DES SYNCHRONISATIONS AVEC REPORTING SERVICES par vfabing
Afin de s'assurer du bon fonctionnement des différentes synchronisations effectuées par les TFS Integration Tools, 2 rapports sont présents dès l'installation. Il suffit alors d'effectuer les manipulations suivantes pour pouvoir les visualiser : Loca...
Cliquez pour lire la suite de l'article par vfabing CSS CONTENT STATE SELECTORS (PERSONNAL DRAFT)CSS CONTENT STATE SELECTORS (PERSONNAL DRAFT) par FREMYCOMPANY
Bonjour à tous, Je viens de publier une proposition comprenant 5 pseudo-classes pour le CSS Working Group ayant trait à l'état de chargement d'un élément (ex: IMG,VIDEO,AUDIO,OBJECT pour l'HTML.). Si le c½ur vous en dit, vous pouvez retrouver cette p...
Cliquez pour lire la suite de l'article par FREMYCOMPANY MBA : POURQUOI FAIRE ET COMMENT LE CHOISIR ?MBA : POURQUOI FAIRE ET COMMENT LE CHOISIR ? par ROMELARD Fabrice
Formation initiale Durant la formation, le découpage classique est le suivant (je donnerai les équivalences Suisse lorsque je les connaîtrais) : Ecole primaire jusqu'au Collège : Formation générale permettant d'obtenir les méthodes...
Cliquez pour lire la suite de l'article par ROMELARD Fabrice Y'A DES ERREURS QUI PEUVENT RENDRE LE DéVELOPPEUR VIOLENTY'A DES ERREURS QUI PEUVENT RENDRE LE DéVELOPPEUR VIOLENT par Aleks
Quand on a ce genre d'erreur sans log :
Et bas on a juste envie de choper le gas de Microsoft qu'a développé ça et lui foutre des baffes de Coboye ! ...
Cliquez pour lire la suite de l'article par Aleks
Forum
RE : ARBRE BINAIRERE : ARBRE BINAIRE par pacotheking
Cliquez pour lire la suite par pacotheking
Logiciels
Academy System (17.2.1.0)ACADEMY SYSTEM (17.2.1.0)Logiciel de gestion des établissements.
- élèves/étudiants (inscription, dossier, absence...)
-... Cliquez pour télécharger Academy System Easy-Planning (1.0.0.1)EASY-PLANNING (1.0.0.1)Basé sur les mêmes principes que MyPlanning, Easy-Planning permet de créer des plannings sous la ... Cliquez pour télécharger Easy-Planning COLLECTOR PLUS (3.00B)COLLECTOR PLUS (3.00B)COLLECTOR PLUS version 3.00B est un logiciel utilisant une base de données alimentée par :
- L... Cliquez pour télécharger COLLECTOR PLUS PONAMEDIA PREMIUM - HELLLOOO FLASH DEMO (V7.4)PONAMEDIA PREMIUM - HELLLOOO FLASH DEMO (V7.4)PONAMEDIA TV DEVIENS HELLLOOO FLASH
LA TV SUR VOTRE ORDINATEUR.
Toute une plateforme Multi... Cliquez pour télécharger PONAMEDIA PREMIUM - HELLLOOO FLASH DEMO LettresFaciles 2011 (8.0.0.1)LETTRESFACILES 2011 (8.0.0.1)LettresFaciles est un logiciel facilitant la création et la rédaction de lettres types.
Son inte... Cliquez pour télécharger LettresFaciles 2011
|