Jeśli mamy trzy funkcje (foo, bar i baz), które są tak złożone ...
foo(bar(), baz())
Czy standard C ++ gwarantuje, że pasek zostanie oceniony przed baz?
Jeśli mamy trzy funkcje (foo, bar i baz), które są tak złożone ...
foo(bar(), baz())
Czy standard C ++ gwarantuje, że pasek zostanie oceniony przed baz?
Odpowiedzi:
Nie, nie ma takiej gwarancji. Nie jest określony zgodnie ze standardem C ++.
Bjarne Stroustrup również mówi to wyraźnie w "Języku programowania C ++", 3. wydanie, sekcja 6.2.2, z pewnym uzasadnieniem:
Lepszy kod można wygenerować bez ograniczeń dotyczących kolejności oceny wyrażeń
Chociaż technicznie odnosi się to do wcześniejszej części tej samej sekcji, która mówi, że kolejność oceny części wyrażenia jest również nieokreślona, tj.
int x = f(2) + g(3); // unspecified whether f() or g() is called first
Z [5.2.2] wywołania funkcji,
Kolejność oceny argumentów jest nieokreślona. Wszystkie skutki uboczne obliczeń wyrażeń argumentów obowiązują przed wprowadzeniem funkcji.
Dlatego nie ma gwarancji, że bar()
będzie działać wcześniej baz()
, tylko to bar()
i baz()
zostanie wywołane wcześniej foo
.
Zwróć również uwagę na [5] Wyrażenia, że:
z wyjątkiem przypadków, w których zaznaczono [np. specjalne reguły dla
&&
i||
], kolejność obliczania operandów poszczególnych operatorów i podwyrażeń poszczególnych wyrażeń oraz kolejność, w jakiej występują skutki uboczne, nie jest określona.
więc nawet jeśli zostały pytaniem, czy bar()
potrwa zanim baz()
się foo(bar() + baz())
kolejność jest nadal nieokreślone.
&
, &&
gwarantuje ocenę od lewej do prawej: drugi argument nie jest oceniany, jeśli pierwszy operand jest false
."
Nie ma określonej kolejności dla bar () i baz () - jedyną rzeczą, o której mówi Standard, jest to, że oba zostaną ocenione przed wywołaniem foo (). Ze standardu C ++, sekcja 5.2.2 / 8:
Kolejność oceny argumentów jest nieokreślona.
bar
, następnie linii 1 baz
, następnie linii 2 bar
itd.), Co również jest miłe. :-)
C ++ 17 określa kolejność oceny dla operatorów, która była nieokreślona do C ++ 17. Zobacz pytanie Jakie są gwarancje kolejności oceny wprowadzone przez C ++ 17? Ale zwróć uwagę na swój wyraz twarzy
foo(bar(), baz())
ma jeszcze nieokreśloną kolejność oceny.
W C ++ 11 odpowiedni tekst można znaleźć w 8.3.6 Default arguments / 9 (moje podkreślenie)
Argumenty domyślne są oceniane przy każdym wywołaniu funkcji. Kolejność obliczania argumentów funkcji jest nieokreślona . W konsekwencji parametry funkcji nie powinny być używane w argumencie domyślnym, nawet jeśli nie są oceniane.
Ta sama słówka jest używana również w standardzie C ++ 14 i znajduje się w tej samej sekcji .
Jak inni już zauważyli, standard nie podaje żadnych wskazówek co do kolejności oceny dla tego konkretnego scenariusza. Ta kolejność oceny jest następnie pozostawiana kompilatorowi, a kompilator może mieć gwarancję.
Należy pamiętać, że standard C ++ jest tak naprawdę językiem, który instruuje kompilator, jak konstruować asembler / kod maszynowy. Norma to tylko jedna część równania. Tam, gdzie standard jest niejednoznaczny lub ma konkretnie zdefiniowaną implementację, należy zwrócić się do kompilatora i zrozumieć, w jaki sposób tłumaczy on instrukcje C ++ na prawdziwy język maszynowy.
Tak więc, jeśli kolejność oceny jest wymaganiem lub przynajmniej ważna, a zgodność z różnymi kompilatorami nie jest wymaganiem, zbadaj, w jaki sposób Twój kompilator ostatecznie połączy to w całość, Twoja odpowiedź może ostatecznie leżeć w tym miejscu. Zauważ, że kompilator może zmienić swoją metodologię w przyszłości