Si nous avons trois fonctions (foo, bar et baz) qui sont composées comme ça ...
foo(bar(), baz())
Y a-t-il une garantie par la norme C ++ que la barre sera évaluée avant baz?
Si nous avons trois fonctions (foo, bar et baz) qui sont composées comme ça ...
foo(bar(), baz())
Y a-t-il une garantie par la norme C ++ que la barre sera évaluée avant baz?
Réponses:
Non, il n'y a pas une telle garantie. Il n'est pas spécifié selon la norme C ++.
Bjarne Stroustrup le dit aussi explicitement dans la section 6.2.2 de la 3e édition de "The C ++ Programming Language", avec quelques raisonnements:
Un meilleur code peut être généré en l'absence de restrictions sur l'ordre d'évaluation des expressions
Bien que techniquement, cela se réfère à une partie antérieure de la même section qui dit que l'ordre d'évaluation des parties d'une expression est également non spécifié, c'est-à-dire
int x = f(2) + g(3); // unspecified whether f() or g() is called first
Il n'y a pas d'ordre spécifié pour bar () et baz () - la seule chose que le Standard dit est qu'ils seront tous les deux évalués avant que foo () ne soit appelé. À partir de la norme C ++, section 5.2.2 / 8:
L'ordre d'évaluation des arguments n'est pas spécifié.
bar
, puis la ligne 1 de baz
, puis la ligne 2 de bar
, etc.), ce qui est également agréable. :-)
Depuis [5.2.2] Appel de fonction,
L'ordre d'évaluation des arguments n'est pas spécifié. Tous les effets secondaires des évaluations d'expressions d'argument prennent effet avant que la fonction ne soit entrée.
Par conséquent, il n'y a aucune garantie qui bar()
fonctionnera avant baz()
, seulement cela bar()
et baz()
sera appelé avant foo
.
Notez également dans [5] Expressions que:
sauf indication contraire [par exemple des règles spéciales pour
&&
et||
], l'ordre d'évaluation des opérandes des opérateurs individuels et des sous-expressions des expressions individuelles, et l'ordre dans lequel les effets secondaires se produisent, n'est pas spécifié.
même si vous demandiez si bar()
courra avant baz()
dans foo(bar() + baz())
, l'ordre est encore non précisée.
&
, &&
garantit une évaluation de gauche à droite: le deuxième opérande n'est pas évalué si le premier opérande l'est false
."
C ++ 17 spécifie l'ordre d'évaluation des opérateurs qui n'était pas spécifié jusqu'à C ++ 17. Voir la question Quelles sont les garanties d'ordre d'évaluation introduites par C ++ 17? Mais note ton expression
foo(bar(), baz())
a toujours un ordre d'évaluation non spécifié.
En C ++ 11, le texte correspondant se trouve dans 8.3.6 Arguments par défaut / 9 (c'est moi qui souligne )
Les arguments par défaut sont évalués chaque fois que la fonction est appelée. L'ordre d'évaluation des arguments de fonction n'est pas spécifié . Par conséquent, les paramètres d'une fonction ne doivent pas être utilisés dans un argument par défaut, même s'ils ne sont pas évalués.
Le même verbiage est également utilisé par la norme C ++ 14 et se trouve dans la même section .
Comme d'autres l'ont déjà souligné, la norme ne donne aucune indication sur l'ordre d'évaluation pour ce scénario particulier. Cet ordre d'évaluation est ensuite laissé au compilateur, et le compilateur peut avoir une garantie.
Il est important de se rappeler que le standard C ++ est en réalité un langage pour instruire un compilateur sur la construction de code assembleur / machine. La norme n'est qu'une partie de l'équation. Lorsque la norme est ambiguë ou est spécifiquement définie par une implémentation, vous devez vous tourner vers le compilateur et comprendre comment il traduit les instructions C ++ en véritable langage machine.
Donc, si l'ordre d'évaluation est une exigence, ou du moins importante, et que la compatibilité entre compilateurs croisés n'est pas une exigence, examinez comment votre compilateur finira par assembler cela, votre réponse pourrait finalement se trouver là. Notez que le compilateur pourrait changer sa méthodologie à l'avenir