Je pense que cette partie du projet de norme concernant l'ordre d'évaluation est pertinente:
1.9 Exécution du programme
...
- Sauf indication contraire, les évaluations d'opérandes d'opérateurs individuels et de sous-expressions d'expressions individuelles ne sont pas séquencées. Les calculs de valeur des opérandes d'un opérateur sont séquencés avant le calcul de valeur du résultat de l'opérateur. Si un effet secondaire sur un objet scalaire n'est pas séquencé par rapport à un autre effet secondaire sur le même objet scalaire ou à un calcul de valeur utilisant la valeur du même objet scalaire, et qu'ils ne sont pas potentiellement simultanés, le comportement n'est pas défini
et aussi:
5.2.2 Appel de fonction
...
- [Remarque: les évaluations de l'expression postfixe et des arguments sont toutes non séquencées les unes par rapport aux autres. Tous les effets secondaires des évaluations d'arguments sont séquencés avant l'entrée de la fonction - note de fin]
Donc, pour votre ligne c.meth1(&nu).meth2(nu);
, considérez ce qui se passe dans l'opérateur en termes d'opérateur d'appel de fonction pour l'appel final à meth2
, afin que nous voyions clairement la ventilation dans l'expression et l'argument postfix nu
:
operator()(c.meth1(&nu).meth2, nu);
Les évaluations de l'expression et de l'argument postfix pour l'appel de fonction final (c'est-à-dire l'expression postfixe c.meth1(&nu).meth2
et nu
) ne sont pas séquencées les unes par rapport aux autres selon la règle d' appel de fonction ci-dessus. Par conséquent, l' effet secondaire du calcul de l'expression de suffixe sur l'objet scalaire ar
n'est pas séquencé par rapport à l'évaluation de l'argument nu
avant l' meth2
appel de fonction. D'après la règle d' exécution du programme ci-dessus, il s'agit d'un comportement non défini.
En d'autres termes, il n'est pas nécessaire que le compilateur évalue l' nu
argument de l' meth2
appel après l' meth1
appel - il est libre de supposer qu'aucun effet secondaire meth1
n'affecte l' nu
évaluation.
Le code d'assemblage produit par ce qui précède contient la séquence suivante dans la main
fonction:
- La variable
nu
est allouée sur la pile et initialisée avec 0.
- Un registre (
ebx
dans mon cas) reçoit une copie de la valeur denu
- Les adresses de
nu
et c
sont chargées dans les registres de paramètres
meth1
est appelé
- Le registre de valeur de retour et la valeur précédemment mise en cache de
nu
dans le ebx
registre sont chargés dans les registres de paramètres
meth2
est appelé
De manière critique, à l'étape 5 ci-dessus, le compilateur permet à la valeur mise en cache nu
de l'étape 2 d'être réutilisée dans l'appel de fonction à meth2
. Ici, il ne tient pas compte de la possibilité qui nu
peut avoir été modifiée par l'appel à meth1
«comportement indéfini» en action.
REMARQUE: Cette réponse a changé en substance par rapport à sa forme originale. Mon explication initiale en termes d'effets secondaires du calcul des opérandes n'étant pas séquencée avant l'appel de fonction final était incorrecte, car ils le sont. Le problème est le fait que le calcul des opérandes eux-mêmes est séquencé de manière indéterminée.