J'ai lu que je devrais éviter l'opérateur d'incrémentation postfix pour des raisons de performances (dans certains cas).
Mais cela n'affecte-t-il pas la lisibilité du code? À mon avis:
for(int i = 0; i < 42; i++);
/* i will never equal 42! */
Ressemble mieux que:
for(int i = 0; i < 42; ++i);
/* i will never equal 42! */
Mais c'est probablement juste par habitude. Certes, je n'en ai pas vu beaucoup d'utilisation ++i
.
Les performances sont-elles mauvaises pour sacrifier la lisibilité, dans ce cas? Ou suis-je simplement aveugle et ++i
plus lisible que i++
?
c++
readability
postfix
Mateen Ulhaq
la source
la source
i++
avant de savoir que cela pouvait affecter les performances++i
, alors j'ai changé. Au début, ce dernier avait l'air un peu étrange, mais après un certain temps, je m'y suis habitué et maintenant, c'est aussi naturel quei++
.++i
eti++
faire des choses différentes dans certains contextes, ne présumez pas qu'elles sont les mêmes.for (type i = 0; i != 42; ++i)
. Non seulement peutoperator++
être surchargé, mais peut aussioperator!=
etoperator<
. L'incrémentation du préfixe n'est pas plus cher que le postfix, pas égal n'est pas plus cher que moins que. Lesquels devrions-nous utiliser?Réponses:
Les faits:
i ++ et ++ i sont également faciles à lire. Vous ne l'aimez pas parce que vous n'y êtes pas habitué, mais il n'y a pratiquement rien de mal à l'interpréter, donc ce n'est plus un travail à lire ou à écrire.
Dans au moins certains cas, l'opérateur postfix sera moins efficace.
Cependant, dans 99,99% des cas, cela n'aura pas d'importance car (a) il agira de toute façon sur un type simple ou primitif et ce n'est un problème que s'il copie un gros objet (b) il ne sera pas dans une performance partie critique du code (c) vous ne savez pas si le compilateur l'optimisera ou non, il peut le faire.
Ainsi, je suggère d'utiliser le préfixe à moins que vous n'ayez spécifiquement besoin que postfix soit une bonne habitude, juste parce que (a) c'est une bonne habitude d'être précis avec d'autres choses et (b) une fois dans une lune bleue, vous aurez l'intention d'utiliser postfix et faites-le dans le mauvais sens: si vous écrivez toujours ce que vous voulez dire, c'est moins probable. Il y a toujours un compromis entre performances et optimisation.
Vous devez utiliser votre bon sens et ne pas micro-optimiser jusqu'à ce que vous en ayez besoin, mais ne pas être manifestement inefficace pour le plaisir. Cela signifie généralement: premièrement, exclure toute construction de code qui est inefficace de manière inacceptable, même dans le code non critique en temps (normalement quelque chose représentant une erreur conceptuelle fondamentale, comme passer des objets de 500 Mo par valeur sans raison); et deuxièmement, de toutes les autres façons d'écrire le code, choisissez la plus claire.
Cependant, ici, je pense que la réponse est simple: je pense que l'écriture d'un préfixe, sauf si vous avez spécifiquement besoin de postfix, est (a) très légèrement plus claire et (b) très légèrement plus susceptible d'être plus efficace, vous devriez donc toujours l'écrire par défaut, mais ne vous en faites pas si vous oubliez.
Il y a six mois, je pensais comme vous, qu'i ++ était plus naturel, mais c'est purement ce à quoi vous êtes habitué.
EDIT 1: Scott Meyers, dans "C ++ plus efficace" auquel je fais généralement confiance, dit que vous devriez en général éviter d'utiliser l'opérateur postfix sur les types définis par l'utilisateur (car la seule implémentation sensée de la fonction d'incrémentation postfix est de faire un copie de l'objet, appelez la fonction d'incrémentation du préfixe pour effectuer l'incrémentation et renvoyez la copie, mais les opérations de copie peuvent être coûteuses).
Donc, nous ne savons pas s'il existe des règles générales sur (a) si cela est vrai aujourd'hui, (b) si cela s'applique également (moins) aux types intrinsèques (c) si vous devez utiliser "++" sur rien de plus qu'une classe d'itérateurs légers. Mais pour toutes les raisons que j'ai décrites ci-dessus, peu importe, faites ce que j'ai dit auparavant.
EDIT 2: Cela fait référence à la pratique générale. Si vous pensez que cela importe dans certains cas spécifiques, vous devez le profiler et le voir. Le profilage est facile et bon marché et fonctionne. Déduire des premiers principes ce qui doit être optimisé est difficile et coûteux et ne fonctionne pas.
la source
i++
plutôt que++i
c'est à cause du nom d'un certain langage de programmation populaire référencé dans cette question / réponse ...Toujours coder le programmeur en premier et l'ordinateur en second.
S'il y a une différence de performances, une fois que le compilateur a jeté un œil expert sur votre code, ET vous pouvez le mesurer ET cela compte - alors vous pouvez le changer.
la source
GCC produit le même code machine pour les deux boucles.
Code C
Code d'assemblage (avec mes commentaires)
la source
Maintenant que cela est hors de notre chemin, faisons notre choix en toute sécurité :
++i
: incrément de préfixe , incrémente la valeur actuelle et donne le résultati++
: incrément de suffixe , copie la valeur, incrémente la valeur actuelle, produit la copieÀ moins qu'une copie de l'ancienne valeur ne soit requise, l'utilisation de l' incrémentation de suffixe est un moyen détourné de faire avancer les choses.
L'inexactitude vient de la paresse, utilisez toujours la construction qui exprime votre intention de la manière la plus directe, il y a moins de chances que le futur responsable puisse mal comprendre votre intention initiale.
Même si c'est (vraiment) mineur ici, il y a des moments où j'ai été vraiment perplexe en lisant le code: je me demandais vraiment si l'intention et l'express réel coïncidaient, et bien sûr, après quelques mois, ils (ou moi) ne se souvenait pas non plus ...
Donc, peu importe si cela vous convient ou non. Embrassez KISS . Dans quelques mois, vous aurez évité vos anciennes pratiques.
la source
En C ++, vous pourriez faire une différence de performances substantielle s'il y a des surcharges d'opérateurs impliquées, en particulier si vous écrivez du code basé sur des modèles et que vous ne savez pas quels itérateurs peuvent être transmis. La logique derrière tout itérateur X peut être à la fois substantielle et significative- c'est-à-dire lent et impossible à optimiser par le compilateur.
Mais ce n'est pas le cas en C, où vous savez que ce ne sera qu'un type trivial, et la différence de performances est triviale et le compilateur peut facilement s'optimiser.
Donc, un conseil: vous programmez en C, ou en C ++, et les questions concernent l'un ou l'autre, pas les deux.
la source
Les performances de l'une ou l'autre opération dépendent fortement de l'architecture sous-jacente. Il faut incrémenter une valeur qui est stockée en mémoire, ce qui signifie que le goulot d'étranglement de von Neumann est le facteur limitant dans les deux cas.
Dans le cas de ++ i, nous devons
Dans le cas d'i ++, nous devons
Les opérateurs ++ et - remontent leur origine au jeu d'instructions PDP-11. Le PDP-11 pourrait effectuer un post-incrémentation automatique sur un registre. Il pourrait également effectuer une pré-décrémentation automatique sur une adresse effective contenue dans un registre. Dans les deux cas, le compilateur ne pouvait tirer parti de ces opérations au niveau de la machine que si la variable en question était une variable "registre".
la source
Si vous voulez savoir si quelque chose est lent, testez-le. Prenez un BigInteger ou équivalent, collez-le dans une boucle for similaire en utilisant les deux idiomes, assurez-vous que l'intérieur de la boucle n'est pas optimisé et chronométrez les deux.
Après avoir lu l'article, je ne le trouve pas très convaincant, pour trois raisons. Premièrement, le compilateur doit être en mesure d'optimiser la création d'un objet qui n'est jamais utilisé. Deuxièmement, le
i++
concept est idiomatique pour les boucles numériques , donc les cas que je peux voir réellement affectés sont limités à. Troisièmement, ils fournissent un argument purement théorique, sans aucun chiffre à l'appui.Sur la base de la raison n ° 1 en particulier, je suppose que lorsque vous effectuez réellement le timing, ils seront juste à côté les uns des autres.
la source
Tout d'abord, cela n'affecte pas la lisibilité de l'OMI. Ce n'est pas ce que vous aviez l'habitude de voir, mais il ne vous faudra que peu de temps pour vous y habituer.
Deuxièmement, à moins que vous n'utilisiez une tonne d'opérateurs de suffixe dans votre code, vous ne verrez probablement pas beaucoup de différence. L'argument principal pour ne pas les utiliser lorsque cela est possible est qu'une copie de la valeur de la var d'origine doit être conservée jusqu'à la fin des arguments où la var d'origine pouvait encore être utilisée. C'est soit 32bits soit 64bits selon l'architecture. Cela équivaut à 4 ou 8 octets ou 0,00390625 ou 0,0078125 Mo. Les chances sont très élevées qu'à moins que vous n'utilisiez une tonne d'entre elles qui doivent être enregistrées pendant une très longue période de temps, avec les ressources informatiques et la vitesse d'aujourd'hui, vous ne remarquerez même pas de différence en passant d'un postfixe à un préfixe.
EDIT: Oubliez cette partie restante car ma conclusion s'est avérée fausse (sauf pour la partie de ++ i et i ++ ne faisant pas toujours la même chose ... c'est toujours vrai).
Il a également été souligné plus tôt qu'ils ne font pas la même chose dans certains cas. Soyez prudent lorsque vous décidez de faire le changement. Je ne l'ai jamais essayé (j'ai toujours utilisé postfix) donc je ne sais pas avec certitude mais je pense que changer de postfix en préfixe donnera des résultats différents: (encore une fois je pourrais me tromper ... dépend du compilateur / interprète aussi)
la source
Je pense que sémantiquement, a
++i
plus de sens quei++
, donc je m'en tiendrai au premier, sauf qu'il est courant de ne pas le faire (comme en Java, où vous devriez l'utiliseri++
parce qu'il est largement utilisé).la source
Il ne s'agit pas uniquement de performances.
Parfois, vous voulez éviter d'implémenter la copie, car cela n'a pas de sens. Et puisque l'utilisation de l'incrément de préfixe ne dépend pas de cela, il est clairement plus simple de s'en tenir à la forme de préfixe.
Et utiliser différents incréments pour les types primitifs et les types complexes ... c'est vraiment illisible.
la source
Sauf si vous en avez vraiment besoin, je m'en tiendrai à ++ i. Dans la plupart des cas, c'est ce que l'on entend. Ce n'est pas très souvent que vous avez besoin d'i ++, et vous devez toujours réfléchir à deux fois lors de la lecture d'une telle construction. Avec ++ i, c'est facile: vous ajoutez 1, vous l'utilisez, puis i est toujours le même.
Donc, je suis entièrement d'accord avec @martin beckett: rendez-vous plus facile, c'est déjà assez difficile.
la source