Ordre d'évaluation dans les paramètres de fonction C ++

89

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?

Clark Gaebel
la source

Réponses:

101

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
Eli Bendersky
la source
Je peux accepter cette réponse en 8 minutes ... Je suppose que je reste un peu dans les parages!
Clark Gaebel
4
Oui, mais un meilleur code pourrait être ÉCRIT (= plus propre) si l'ordre d'évaluation des expressions était STRICT, ce qui est généralement beaucoup plus important que la génération de code. Voir cet exemple: stackoverflow.com/questions/43612592/... Alors là, Stroustrup.
Bill Kotsias
1
Si la commande est importante, vous êtes libre de faire le séquençage vous-même. Agir autrement entraînerait toujours un coût pour quelque chose qui n'a pas toujours (rarement?) D'importance. Je pense que la politique de ne pas payer pour ce que vous n'utilisez pas est la seule chose sur laquelle la plupart des programmeurs C ++ sont d'accord.
tweej
3
Ne devrait-il pas s'agir d'un «comportement non spécifié» au lieu de «non défini»?
GoodDeeds
1
@ChrisDodd voter contre une réponse acceptée en raison de l'utilisation du mot "non défini" par rapport à "non spécifié" me semble être un pédantisme malveillant ... Je n'ai pas dit que c'était un "comportement non défini", et sinon, "non défini" et "non spécifié" semblent synonyme? Dans tous les cas, proposer une modification à la réponse aurait été un moyen plus productif d'en discuter
Eli Bendersky
20

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é.


la source
4
Le fait qu'ils soient évalués avant foo () est au moins un peu rassurant.
Bill Kotsias
1
@BillKotsias La norme dit également que les appels de fonction ne peuvent pas se chevaucher (c'est-à-dire qu'une implémentation ne peut pas exécuter la ligne 1 de bar, puis la ligne 1 de baz, puis la ligne 2 de bar, etc.), ce qui est également agréable. :-)
melpomene
20

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.

Daniel Trebbien
la source
4
Un exemple de "note spéciale" de [5.14] Opérateur logique ET: "Contrairement &, &&garantit une évaluation de gauche à droite: le deuxième opérande n'est pas évalué si le premier opérande l'est false."
Daniel Trebbien
2

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 .

R Sahu
la source
0

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

Programmeur érudit
la source