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).meth2i 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 arjest bez kolejności w stosunku do oceny argumentu nuprzed meth2wywołaniem funkcji. Zgodnie z powyższą regułą wykonywania programu jest to niezdefiniowane zachowanie.
Innymi słowy, kompilator nie musi oceniać nuargumentu meth2wywołania po meth1wywołaniu - może zakładać, że nie ma skutków ubocznych meth1wpływania na nuocenę.
Kod asemblera utworzony przez powyższe zawiera następującą sekwencję w mainfunkcji:
- Zmienna
nujest przydzielana na stosie i inicjalizowana z wartością 0.
- Rejestr (
ebxw moim przypadku) otrzymuje kopię wartościnu
- Adresy
nui csą ładowane do rejestrów parametrów
meth1 jest nazywany
- Rejestr wartość powrotu a poprzednio buforowane wartość z
nuw ebxrejestrze są ładowane do rejestrów parametrów
meth2 jest nazywany
Co najważniejsze, w kroku 5 powyżej kompilator umożliwia nuponowne użycie zbuforowanej wartości z kroku 2 w wywołaniu funkcji meth2. W tym przypadku pomija możliwość, która numogł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.