web-dev-qa-db-fra.com

++ i ou i ++ dans les boucles ??

Duplicata possible:
Y a-t-il une différence de performances entre i ++ et ++ i en C++?

Y a-t-il une raison pour laquelle certains programmeurs écrivent ++i dans une boucle for normale au lieu d'écrire i++?

53
Ismail Marmoush

Pour les entiers, il n'y a pas de différence entre pré et post-incrémentation.

Si i est un objet d'une classe non triviale, alors ++i est généralement préféré, car l'objet est modifié puis évalué, tandis que i++ modifie après évaluation, nécessite donc une copie.

81

++i est légèrement plus efficace en raison de sa sémantique:

++i;  // Fetch i, increment it, and return it
i++;  // Fetch i, copy it, increment i, return copy

Pour les indices de type int, le gain d'efficacité est minime (le cas échéant). Pour les itérateurs et autres objets plus lourds, éviter cette copie peut être une vraie victoire (en particulier si le corps de la boucle ne contient pas beaucoup de travail).

Par exemple, considérons la boucle suivante en utilisant une classe BigInteger théorique fournissant des entiers de précision arbitraires (et donc une sorte d'internes de type vectoriel):

std::vector<BigInteger> vec;
for (BigInteger i = 0; i < 99999999L; i++) {
  vec.Push_back(i);
}

Cette opération i ++ comprend la construction de la copie (c'est-à-dire l'opérateur nouveau, la copie chiffre par chiffre) et la destruction (suppression opérateur) pour une boucle qui ne fera rien de plus que de faire essentiellement une copie de plus de l'objet d'index. Essentiellement, vous avez doublé le travail à faire (et probablement augmenté la fragmentation de la mémoire) en utilisant simplement l'incrément postfix où le préfixe aurait été suffisant.

102
Drew Hall

++i est un pré-incrément; i++ est post-incrément.
L'inconvénient du post-incrément est qu'il génère une valeur supplémentaire; il retourne ne copie de l'ancienne valeur tout en modifiant i. Ainsi, vous devriez l'éviter lorsque cela est possible.

7
Richard

Avec des entiers, c'est la préférence.

Si la variable de boucle est une classe/un objet, cela peut faire une différence (seul le profilage peut vous dire si c'est une différence significative), car la version post-incrémentation nécessite que vous créiez une copie de cet objet qui est supprimée.

Si la création de cette copie est une opération coûteuse, vous payez cette dépense une fois pour chaque fois que vous passez par la boucle, sans aucune raison.

Si vous avez l'habitude de toujours utiliser ++i pour les boucles, vous n'avez pas besoin de vous arrêter et de vous demander si ce que vous faites dans cette situation particulière est logique. Vous l'êtes toujours.

4
bgporter

Il y a une raison à cela: les performances. i ++ génère une copie, et c'est un gaspillage si vous la jetez immédiatement. Certes, le compilateur peut optimiser cette copie si i est une primitive, mais ce n'est pas le cas si ce n'est pas le cas. Voir cette question.

2
wilhelmtell

Aucun compilateur valant son poids en sel ne fonctionnera différemment entre

for(int i=0; i<10; i++)

et

for(int i=0;i<10;++i)

++ i et i ++ ont le même coût. La seule chose qui diffère est que la valeur de retour de ++ i est i + 1 tandis que la valeur de retour de i ++ est i.

Donc, pour ceux qui préfèrent ++ i, il n'y a probablement aucune justification valable, juste une préférence personnelle.

EDIT: C'est mal pour les cours, comme dit dans tous les autres articles. i ++ générera une copie si i est une classe.

1
rtpg

Comme d'autres l'ont déjà noté, le pré-incrément est généralement plus rapide que le post-incrément pour les types définis par l'utilisateur. Pour comprendre pourquoi il en est ainsi, regardez le modèle de code typique pour implémenter les deux opérateurs:

Foo& operator++()
{
    some_member.increase();
    return *this;
}

Foo operator++(int dummy_parameter_indicating_postfix)
{
    Foo copy(*this);
    ++(*this);
    return copy;
}

Comme vous pouvez le voir, la version du préfixe modifie simplement l'objet et le renvoie par référence.

La version postfix, d'autre part, doit faire une copie avant que l'incrémentation réelle soit effectuée, puis cette copie est recopiée vers l'appelant par valeur. Il est évident d'après le code source que la version postfixe doit faire plus de travail, car elle inclut un appel à la version préfixe: ++(*this);

Pour les types intégrés, cela ne fait aucune différence tant que vous supprimez la valeur, c'est-à-dire tant que vous n'incorporez pas ++i Ou i++ Dans une expression plus grande telle que a = ++i Ou b = i++.

1
fredoverflow

Préférence personnelle.

Habituellement. Parfois, cela compte, mais, pour ne pas sembler un idiot ici, mais si vous devez demander, ce n'est probablement pas le cas.

0
John Dibling

lorsque vous utilisez postfix, il instancie plus d'objets en mémoire. Certaines personnes disent qu'il est préférable d'utiliser l'opérateur de suffixe dans la boucle for

0
Yevhen