Je lisais "Le langage de programmation C ++" de Stroustrup, où il dit que deux façons d'ajouter quelque chose à une variable
x = x + a;
et
x += a;
Il préfère +=
parce qu'il est probablement mieux mis en œuvre. Je pense qu'il veut dire que ça marche aussi plus vite.
Mais est-ce vraiment? Si cela dépend du compilateur et d'autres choses, comment puis-je vérifier?
c++
performance
operators
Chiffa
la source
la source
Réponses:
Tout vaut compilateur son sel va générer exactement la même séquence de langage machine pour les deux constructions pour tout type intégré (
int
,float
, etc.) tant que la déclaration est vraiment aussi simple quex = x + a;
et l' optimisation est activée . (Notamment, GCC-O0
, qui est le mode par défaut, effectue des anti-optimisations , telles que l'insertion de magasins complètement inutiles dans la mémoire, afin de s'assurer que les débogueurs peuvent toujours trouver des valeurs de variable.)Si la déclaration est plus compliquée, cependant, elles peuvent être différentes. Supposons
f
qu'une fonction renvoie un pointeur, alorsn'appelle
f
qu'une seule fois, alors quel'appelle deux fois. S'il
f
a des effets secondaires, l'un des deux sera faux (probablement le dernier). Même s'ilf
n'a pas d'effets secondaires, le compilateur peut ne pas être en mesure d'éliminer le deuxième appel, ce dernier peut donc être plus lent.Et puisque nous parlons de C ++ ici, la situation est entièrement différente pour les types de classes qui surchargent
operator+
etoperator+=
. Six
c'est un tel type, alors - avant l'optimisation - sex += a
traduit parx.operator+=(a);
alors que se
x = x + a
traduit parauto TEMP(x.operator+(a)); x.operator=(TEMP);
Maintenant, si la classe est correctement écrite et que l'optimiseur du compilateur est assez bon, les deux finiront par générer le même langage machine, mais ce n'est pas une chose sûre comme c'est le cas pour les types intégrés. C'est probablement ce à quoi Stroustrup pense quand il encourage l'utilisation
+=
.la source
expr
àvar
isvar+=expr
et l'écrire dans l'autre sens déroutera les lecteurs.*f() = *f() + a;
d' écrire, vous voudrez peut-être jeter un coup d'œil à ce que vous essayez vraiment de réaliser ...1
est une constante,a
peut être un type volatile, défini par l'utilisateur ou autre. Complètement différent. En fait, je ne comprends pas comment cela s'est même fermé.Vous pouvez vérifier en regardant le démontage, qui sera le même.
Pour les types de base , les deux sont également rapides.
Ceci est une sortie générée par une version de débogage (c'est-à-dire sans optimisations):
a += x; 010813BC mov eax,dword ptr [a] 010813BF add eax,dword ptr [x] 010813C2 mov dword ptr [a],eax a = a + x; 010813C5 mov eax,dword ptr [a] 010813C8 add eax,dword ptr [x] 010813CB mov dword ptr [a],eax
Pour les types définis par l'utilisateur , où vous pouvez surcharger
operator +
etoperator +=
, cela dépend de leurs implémentations respectives.la source
a
est 1 etx
estvolatile
le compilateur pourrait générerinc DWORD PTR [x]
. C'est lent.operator +
de ne rien faire etoperator +=
de calculer le 100000e nombre premier, puis de revenir. Bien sûr, ce serait une chose stupide à faire, mais c'est possible.++x
ettemp = x + 1; x = temp;
, alors il devrait très probablement être écrit en assembly plutôt qu'en c ++ ...Oui! C'est plus rapide à écrire, plus rapide à lire et plus rapide à comprendre, pour ce dernier dans le cas où cela
x
pourrait avoir des effets secondaires. C'est donc globalement plus rapide pour les humains. Le temps humain en général coûte beaucoup plus cher que le temps informatique, c'est donc ce que vous vouliez savoir. Droite?la source
Cela dépend vraiment du type de x et a et de l'implémentation de +. Pour
le compilateur doit créer un T temporaire pour contenir la valeur de x + a pendant qu'il l'évalue, qu'il peut ensuite affecter à x. (Il ne peut pas utiliser x ou a comme espace de travail pendant cette opération).
Pour x + = a, il n'a pas besoin d'un fichier temporaire.
Pour les types triviaux, il n'y a aucune différence.
la source
La différence entre
x = x + a
etx += a
est la quantité de travail que la machine doit effectuer - certains compilateurs peuvent (et le font généralement) l'optimiser, mais généralement, si nous ignorons l'optimisation pendant un certain temps, ce qui se passe est que dans l'ancien extrait de code, le la machine doit rechercher la valeurx
deux fois, tandis que dans le dernier, cette recherche ne doit se produire qu'une seule fois.Cependant, comme je l'ai mentionné, aujourd'hui, la plupart des compilateurs sont suffisamment intelligents pour analyser les instructions et réduire les instructions machine résultantes requises.
PS: Première réponse sur Stack Overflow!
la source
Comme vous avez étiqueté ce C ++, il n'y a aucun moyen de savoir à partir des deux déclarations que vous avez publiées. Vous devez savoir ce qu'est «x» (c'est un peu comme la réponse «42»). S'il
x
s'agit d'un POD, cela ne fera pas vraiment de différence. Cependant, six
est une classe, il peut y avoir des surcharges pour les méthodesoperator +
etoperator +=
qui pourraient avoir des comportements différents conduisant à des temps d'exécution très différents.la source
Si vous dites que
+=
vous rendez la vie beaucoup plus facile pour le compilateur. Pour que le compilateur reconnaisse quex = x+a
c'est la même chosex += a
, le compilateur doitanalysez le côté gauche (
x
) pour vous assurer qu'il n'a pas d'effets secondaires et se réfère toujours à la même valeur l. Par exemple, cela pourrait l'êtrez[i]
, et il faut s'assurer que les deuxz
eti
ne changent pas.analysez le côté droit (
x+a
) et assurez-vous qu'il s'agit d'une sommation, et que le côté gauche apparaît une et une seule fois sur le côté droit, même s'il pourrait être transformé, comme dansz[i] = a + *(z+2*0+i)
.Si ce que vous entendez est d'ajouter
a
àx
, l'auteur du compilateur apprécie quand vous dites tout ce que vous voulez dire. De cette façon, vous n'exercez pas la partie du compilateur dont l'auteur espère qu'il / elle a éliminé tous les bugs, et cela ne vous facilite pas vraiment la vie, à moins que vous ne puissiez honnêtement pas sortir la tête. du mode Fortran.la source
Pour un exemple concret, imaginez un type de nombre complexe simple:
struct complex { double x, y; complex(double _x, double _y) : x(_x), y(_y) { } complex& operator +=(const complex& b) { x += b.x; y += b.y; return *this; } complex operator +(const complex& b) { complex result(x+b.x, y+b.y); return result; } /* trivial assignment operator */ }
Pour le cas a = a + b, il doit créer une variable temporaire supplémentaire, puis la copier.
la source
Vous posez la mauvaise question.
Il est peu probable que cela améliore les performances d'une application ou d'une fonctionnalité. Même si c'était le cas, le moyen de le savoir est de profiler le code et de savoir comment il vous affecte à coup sûr. Au lieu de se soucier à ce niveau de ce qui est le plus rapide, il est beaucoup plus important de penser en termes de clarté, d'exactitude et de lisibilité.
Cela est particulièrement vrai si l'on considère que, même s'il s'agit d'un facteur de performance important, les compilateurs évoluent au fil du temps. Quelqu'un peut trouver une nouvelle optimisation et la bonne réponse aujourd'hui peut devenir fausse demain. C'est un cas classique d'optimisation prématurée.
Cela ne veut pas dire que la performance n'a pas d'importance du tout ... C'est simplement la mauvaise approche pour atteindre vos objectifs de performance. La bonne approche consiste à utiliser des outils de profilage pour savoir où votre code passe réellement son temps, et donc où concentrer vos efforts.
la source
Je pense que cela devrait dépendre de la machine et de son architecture. Si son architecture permet l'adressage indirect de la mémoire, le rédacteur du compilateur PEUT simplement utiliser ce code à la place (pour l'optimisation):
mov $[y],$ACC iadd $ACC, $[i] ; i += y. WHICH MIGHT ALSO STORE IT INTO "i"
Alors que,
i = i + y
pourrait être traduit en (sans optimisation):Cela dit, d'autres complications telles que if
i
est une fonction renvoyant un pointeur, etc. doivent également être envisagées. La plupart des compilateurs de niveau production, y compris GCC, produisent le même code pour les deux instructions (si ce sont des entiers).la source
Non, les deux manières sont gérées de la même manière.
la source