web-dev-qa-db-fra.com

Incrémentation en C ++ - Quand utiliser x ++ ou ++ x?

J'apprends actuellement le C++ et j'ai appris l'incrémentation il y a quelque temps. Je sais que vous pouvez utiliser "++ x" pour effectuer l'incrémentation avant et "x ++" pour le faire après.

Pourtant, je ne sais vraiment pas quand utiliser l'un ou l'autre ... Je n'ai jamais vraiment utilisé "++ x" et les choses ont toujours bien fonctionné jusqu'à présent. Alors, quand dois-je l'utiliser?

Exemple: dans une boucle for, quand est-il préférable d'utiliser "++ x"?

Aussi, quelqu'un pourrait-il expliquer exactement comment fonctionnent les différentes incrémentations (ou décrémentations)? J'apprécierai vraiment cela.

80
Jesse Emond

Ce n'est pas une question de préférence, mais de logique.

x++ incrémente la valeur de la variable x after traite l'instruction en cours.

++x incrémente la valeur de la variable x before traite l'instruction en cours.

Alors décidez simplement de la logique que vous écrivez.

x += ++i incrémentera i et ajoutera i + 1 à x. x += i++ ajoutera i à x, puis incrémentera i.

98
Oliver Friedrich

Scott Meyers vous dit de préférer le préfixe sauf dans les cas où la logique voudrait que postfix soit approprié.

Item # 6 "Plus efficace C++" - c'est une autorité suffisante pour moi.

Pour ceux qui ne possèdent pas le livre, voici les citations pertinentes. A partir de la page 32:

De vos jours en tant que programmeur C, vous pouvez vous rappeler que la forme de préfixe de l'opérateur d'incrémentation est parfois appelée "incrémentation et extraction", alors que la forme postfixée est souvent appelée "extraction et incrémentation". Les deux phrases sont importantes à retenir, car elles agissent toutes comme des spécifications formelles ...

Et à la page 34:

Si vous êtes du genre à vous soucier de l'efficacité, vous vous êtes probablement mis à transpirer lorsque vous avez vu pour la première fois la fonction d'incrémentation de postfix. Cette fonction doit créer un objet temporaire pour sa valeur de retour et l'implémentation ci-dessus crée également un objet temporaire explicite qui doit être construit et détruit. La fonction d'incrément de préfixe n'a pas de tels temporaires ...

45
duffymo

De cppreference lors de l'incrémentation des itérateurs:

Vous devriez préférer l'opérateur de pré-incrémentation (++ iter) à l'opérateur de post-incrémentation (iter ++) si vous n'allez pas utiliser l'ancienne valeur. Le post-incrément est généralement implémenté comme suit:

   Iter operator++(int)   {
     Iter tmp(*this); // store the old value in a temporary object
     ++*this;         // call pre-increment
     return tmp;      // return the old value   }

De toute évidence, c'est moins efficace que la pré-incrémentation.

La pré-incrémentation ne génère pas l'objet temporaire. Cela peut faire une différence significative si votre objet est coûteux à créer.

20
Phillip Ngan

Je veux juste noter que le code généré est souvent le même si vous utilisez une incrémentation pré/post où la sémantique (de pré/post) n'a pas d'importance.

exemple:

pre.cpp:

#include <iostream>

int main()
{
  int i = 13;
  i++;
  for (; i < 42; i++)
    {
      std::cout << i << std::endl;
    }
}

post.cpp:

#include <iostream>

int main()
{

  int i = 13;
  ++i;
  for (; i < 42; ++i)
    {
      std::cout << i << std::endl;
    }
}

_

$> g++ -S pre.cpp
$> g++ -S post.cpp
$> diff pre.s post.s   
1c1
<   .file   "pre.cpp"
---
>   .file   "post.cpp"
7
chub

La chose la plus importante à garder à l’esprit, imo, est que x ++ doit renvoyer la valeur avant que l’incrément n’ait réellement eu lieu - par conséquent, il doit effectuer une copie temporaire de l’objet (incrémentation préalable). Cela est moins efficace que ++ x, qui est incrémenté sur place et renvoyé.

Une autre chose à noter, cependant, est que la plupart des compilateurs seront en mesure d’optimiser ces choses inutiles lorsque cela sera possible, par exemple les deux options mèneront au même code ici:

for (int i(0);i<10;++i)
for (int i(0);i<10;i++)
6
rmn

Je suis d’accord avec @BeowulfOF, bien que pour des raisons de clarté, je recommanderais toujours de scinder les déclarations de manière à ce que la logique soit parfaitement claire, c’est-à-dire:

i++;
x += i;

ou

x += i;
i++;

Donc, ma réponse est que si vous écrivez du code clair, alors cela devrait rarement compter (et si cela compte, votre code n'est probablement pas assez clair).

2
Bids

Je voulais juste souligner de nouveau que ++ x devrait être plus rapide que x ++ (surtout si x est un objet de type arbitraire). Par conséquent, sauf si cela est requis pour des raisons logiques, ++ x devrait être utilisé.

2
Shailesh Kumar

Vous avez bien expliqué la différence. Tout dépend si vous voulez que x augmente progressivement avant ou après chaque exécution dans une boucle. Cela dépend de la logique de votre programme, de ce qui est approprié.

Une différence importante en ce qui concerne les itérateurs STL (qui implémentent également ces opérateurs) est que ++ crée une copie de l'objet pointé par l'itérateur, puis l'incrémente, puis renvoie la copie. ++ d'autre part l'incrémentation en premier, puis renvoie une référence à l'objet pointé par l'itérateur. Ceci est principalement pertinent lorsque chaque performance compte ou lorsque vous implémentez votre propre itérateur STL.

Edit: correction du mixage des notations de préfixes et suffixes

1
Björn Pollex

La forme postfixée de ++, - l’opérateur suit la règle se-then-change,

La forme de préfixe (++ x, - x) suit la règle change-then-use.

Exemple 1:

Lorsque plusieurs valeurs sont mises en cascade avec << using cout , les calculs (le cas échéant) ont lieu de droite à gauche mais l'impression se fait de gauche à droite. -right eg, (si val si au départ 10)

 cout<< ++val<<" "<< val++<<" "<< val;

aboutira à

12    10    10 

Exemple 2:

Dans Turbo C++, si plusieurs occurrences de ++ ou (sous n’importe quelle forme) sont trouvées dans une expression, toutes les formes de préfixe sont calculées d’abord, puis l’expression est évaluée et enfin les formes de postfix sont calculées, par exemple:

int a=10,b;
b=a++ + ++a + ++a + a;
cout<<b<<a<<endl;

Sa sortie en Turbo C++ sera

48 13

Considérant que sa sortie dans le compilateur moderne sera (parce qu'ils suivent les règles strictement)

45 13
  • Remarque: l'utilisation multiple d'opérateurs d'incrémentation/décrémentation sur la même variable dans une expression n'est pas recommandée. Le traitement/les résultats de tels
    Les expressions varient d'un compilateur à l'autre.
0
Sunil Dhillon

Comprendre la syntaxe de la langue est important pour la clarté du code. Pensez à copier une chaîne de caractères, par exemple avec post-incrémentation:

char a[256] = "Hello world!";
char b[256];
int i = 0;
do {
  b[i] = a[i];
} while (a[i++]);

Nous voulons que la boucle s'exécute en rencontrant le caractère zéro (qui teste false) à la fin de la chaîne. Cela nécessite de tester la valeur pré-incrémentée et également d’incrémenter l’index. Mais pas nécessairement dans cet ordre - une façon de coder ceci avec la pré-incrémentation serait:

int i = -1;
do {
  ++i;
  b[i] = a[i];
} while (a[i]);

C’est une question de goût qui est plus claire et si la machine dispose de nombreux registres, le temps d’exécution devrait être identique, même si un [i] est une fonction coûteuse ou qui a des effets secondaires. Une différence significative pourrait être la valeur de sortie de l'index.

0
shkeyser