Myślę, że ta część projektu normy dotycząca kolejności ocen jest istotna:
1.9 Wykonanie programu
...
- O ile nie zaznaczono inaczej, oceny operandów poszczególnych operatorów i podwyrażeń poszczególnych wyrażeń nie są sekwencjonowane. Obliczenia wartości operandów operatora są sekwencjonowane przed obliczeniem wartości wyniku operatora. Jeśli efekt uboczny na obiekcie skalarnym nie jest sekwencjonowany względem innego efektu ubocznego tego samego obiektu skalarnego lub obliczenia wartości przy użyciu wartości tego samego obiektu skalarnego i nie są one potencjalnie współbieżne, zachowanie jest niezdefiniowane
i również:
5.2.2 Wywołanie funkcji
...
- [Uwaga: Obliczenia wyrażenia z przyrostkiem i argumentów nie mają kolejności względem siebie. Wszystkie skutki uboczne oceny argumentów są sekwencjonowane przed wejściem do funkcji - uwaga końcowa]
Więc dla twojej linii c.meth1(&nu).meth2(nu);
zastanów się, co dzieje się w operatorze pod względem operatora wywołania funkcji dla końcowego wywołania meth2
, więc wyraźnie widzimy podział na wyrażenie i argument z przyrostka nu
:
operator()(c.meth1(&nu).meth2, nu);
Wartości wyrażenia przyrostka i argumentu dla końcowego wywołania funkcji (tj. Wyrażenia przyrostka c.meth1(&nu).meth2
i nu
) nie są sekwencjonowane względem siebie, zgodnie z powyższą regułą wywołania funkcji . Dlatego efekt uboczny obliczania wyrażenia postfiksowego na obiekcie skalarnym ar
jest bez kolejności w stosunku do oceny argumentu nu
przed meth2
wywołaniem funkcji. Zgodnie z powyższą regułą wykonywania programu jest to niezdefiniowane zachowanie.
Innymi słowy, kompilator nie musi oceniać nu
argumentu meth2
wywołania po meth1
wywołaniu - może zakładać, że nie ma skutków ubocznych meth1
wpływania na nu
ocenę.
Kod asemblera utworzony przez powyższe zawiera następującą sekwencję w main
funkcji:
- Zmienna
nu
jest przydzielana na stosie i inicjalizowana z wartością 0.
- Rejestr (
ebx
w moim przypadku) otrzymuje kopię wartościnu
- Adresy
nu
i c
są ładowane do rejestrów parametrów
meth1
jest nazywany
- Rejestr wartość powrotu a poprzednio buforowane wartość z
nu
w ebx
rejestrze są ładowane do rejestrów parametrów
meth2
jest nazywany
Co najważniejsze, w kroku 5 powyżej kompilator umożliwia nu
ponowne użycie zbuforowanej wartości z kroku 2 w wywołaniu funkcji meth2
. W tym przypadku pomija możliwość, która nu
mogła zostać zmieniona przez wezwanie do meth1
- „niezdefiniowanego zachowania” w akcji.
UWAGA: Ta odpowiedź zmieniła się zasadniczo w stosunku do pierwotnej formy. Moje początkowe wyjaśnienie w zakresie skutków ubocznych obliczania argumentów, które nie były sekwencjonowane przed ostatecznym wywołaniem funkcji, było niepoprawne, ponieważ tak jest. Problem polega na tym, że obliczenia samych operandów są nieokreślone.