préfixe y postfixe sont des candidats parfaits pour les questions d'examen.
a = 0;
b = a++; // use the value and then increment --> a: 1, b: 0
a = 0;
b = ++a; // increment and then use the value --> a: 1, b: 1
+=
et sa sœur -=
sont des solutions plus générales, principalement destinées à être utilisées avec différents numéros. On pourrait même dire qu'elles sont redondantes lorsqu'elles sont utilisées avec 1
. Lorsqu'il est utilisé avec 1
ils agissent principalement en tant que préfixe opération. En fait, sur ma machine, ils produisent le même code machine. Vous pouvez essayer en utilisant un programme d'exemple tel que :
void foo() {
int a, b;
a = 0;
// use one of these four at a time
b = a++; // first case (different)
b = ++a; // second case
b = (a += 1); // third case
b = (a = a + 1); // fourth case
}
int main() {
foo();
return 0;
}
et le démontage en gdb
ce qui donnerait :
premier cas ( a++
) (différent)
(gdb) disassemble foo
Dump of assembler code for function foo:
0x00000000004004b4 <+0>: push %rbp
0x00000000004004b5 <+1>: mov %rsp,%rbp
0x00000000004004b8 <+4>: movl $0x0,-0x8(%rbp)
0x00000000004004bf <+11>: mov -0x8(%rbp),%eax
0x00000000004004c2 <+14>: mov %eax,-0x4(%rbp)
0x00000000004004c5 <+17>: addl $0x1,-0x8(%rbp)
0x00000000004004c9 <+21>: pop %rbp
0x00000000004004ca <+22>: retq
End of assembler dump.
deuxième cas ( ++a
)
(gdb) disassemble foo
Dump of assembler code for function foo:
0x00000000004004b4 <+0>: push %rbp
0x00000000004004b5 <+1>: mov %rsp,%rbp
0x00000000004004b8 <+4>: movl $0x0,-0x8(%rbp)
0x00000000004004bf <+11>: addl $0x1,-0x8(%rbp)
0x00000000004004c3 <+15>: mov -0x8(%rbp),%eax
0x00000000004004c6 <+18>: mov %eax,-0x4(%rbp)
0x00000000004004c9 <+21>: pop %rbp
0x00000000004004ca <+22>: retq
End of assembler dump.
troisième cas ( a += 1
)
(gdb) disassemble foo
Dump of assembler code for function foo:
0x00000000004004b4 <+0>: push %rbp
0x00000000004004b5 <+1>: mov %rsp,%rbp
0x00000000004004b8 <+4>: movl $0x0,-0x8(%rbp)
0x00000000004004bf <+11>: addl $0x1,-0x8(%rbp)
0x00000000004004c3 <+15>: mov -0x8(%rbp),%eax
0x00000000004004c6 <+18>: mov %eax,-0x4(%rbp)
0x00000000004004c9 <+21>: pop %rbp
0x00000000004004ca <+22>: retq
End of assembler dump.
quatrième cas ( a = a + 1
)
(gdb) disassemble foo
Dump of assembler code for function foo:
0x00000000004004b4 <+0>: push %rbp
0x00000000004004b5 <+1>: mov %rsp,%rbp
0x00000000004004b8 <+4>: movl $0x0,-0x8(%rbp)
0x00000000004004bf <+11>: addl $0x1,-0x8(%rbp)
0x00000000004004c3 <+15>: mov -0x8(%rbp),%eax
0x00000000004004c6 <+18>: mov %eax,-0x4(%rbp)
0x00000000004004c9 <+21>: pop %rbp
0x00000000004004ca <+22>: retq
End of assembler dump.
Comme vous pouvez le voir, ils produisent le même code machine même sans que les optimisations du compilateur soient activées, à l'exception du premier cas qui a addl
après mov
s. Cela signifie que vous devriez utiliser celui que vous aimez en tant qu'utilisateur et laisser les compilateurs faire le reste.
Enfin, notez que les opérateurs cousins *=
y /=
n'ont pas postfixe y préfixe des contreparties.
0 votes
Vous ne devez pas vous préoccuper de l'implémentation, mais uniquement de la signification de l'expression. La manière dont le compilateur implémente le code sous-jacent n'est pas pertinente et le compilateur choisira la méthode la plus rapide pour implémenter le sens de l'opération (dans ce cas, incrémenter num de 1), qui sera probablement exactement la même pour POD.
1 votes
@DeadMG Le comportement défini a été restauré :D
25 votes
J'ai 63 ans. Que signifie "UB" ?
1 votes
@TomWetmore Comportement non défini .
1 votes
Pour ce qui est de l'efficacité, comme je l'ai appris dans un cours, ++num est plus rapide que num++ (si le but est seulement d'incrémenter la valeur numérique).
0 votes
@URL87 : Généralisation excessive (par vous, et non par votre professeur, j'en suis sûr). Lorsque l'on parle de POD, il n'y a absolument aucune différence. Lorsque nous parlons d'itérateurs, le modèle standard d'implémentation des itérateurs rendra la version pré-incrémentée plus efficace puisqu'une copie n'est pas nécessaire. Dans tous les autres cas, cela dépendra de l'implémentation exacte. Mais en règle générale, il est préférable de préférer la version pré-incrémentée à la version post-incrémentée en raison de l'omniprésence des itérateurs.
0 votes
@LokiAstari : alors pourquoi n'y a-t-il pas de différence dans POD ? Il n'y a pas de différence dans l'implémentation de int - dans le préfixe, il faut retourner (*this), mais dans le postfixe, il faut retourner new object, dans ce cas - new int. Apparemment, c'est vrai dans tous les cas, et pas seulement pour les itérateurs.
0 votes
@URL87 : Regardez l'assemblage généré.