Порядок оценки в параметрах функции C ++

93

Если у нас есть три функции (foo, bar и baz), которые составлены так ...

foo(bar(), baz())

Есть ли гарантия по стандарту C ++, что bar будет оценен до baz?

Кларк Гебель
источник

Ответы:

103

Нет, такой гарантии нет. Он не определен в соответствии со стандартом C ++.

Бьярн Страуструп также прямо говорит об этом в разделе 6.2.2 3-го издания «Язык программирования C ++», с некоторыми аргументами:

Лучший код может быть сгенерирован без ограничений на порядок оценки выражений

Хотя технически это относится к более ранней части того же раздела, в которой говорится, что порядок оценки частей выражения также не определен, т.е.

int x = f(2) + g(3);   // unspecified whether f() or g() is called first
Эли Бендерский
источник
Я могу принять этот ответ через 8 минут ... Думаю, я немного задержусь!
Clark Gaebel
5
Да, но лучший код можно было бы НАПИСАТЬ (= чище), если бы порядок оценки выражений был СТРОГО, что обычно намного важнее, чем генерация кода. См. Этот пример: stackoverflow.com/questions/43612592/… Итак, Страуструп.
Билл
1
Если порядок имеет значение, вы можете сами выполнить последовательность. В противном случае всегда придется платить за то, что не всегда (редко?) Имеет значение. Я думаю, что политика отказа от оплаты того, что вы не используете, - единственное, с чем согласны большинство программистов на C ++.
tweej 02
3
Разве это не должно быть «неопределенное поведение» вместо «неопределенного»?
GoodDeeds 06
1
@ChrisDodd, отклоняющий принятый ответ из-за использования слова "undefined" против "неопределенного", кажется мне злонамеренным педантизмом ... Я не говорил, что это "неопределенное поведение", а в остальном "undefined" и "неопределенный" кажутся синоним? В любом случае, предложение отредактировать ответ было бы более продуктивным способом обсудить это
Эли Бендерский
21

Из [5.2.2] Вызов функции,

Порядок оценки аргументов не указан. Все побочные эффекты оценок выражения аргумента вступают в силу до того, как функция будет введена.

Следовательно, нет никакой гарантии, что он bar()будет запущен раньше baz(), только то bar()и baz()будет вызываться раньше foo.

Также обратите внимание на [5] Expressions, что:

За исключением случаев, когда это указано [например, специальные правила для &&и ||], порядок оценки операндов отдельных операторов и подвыражений отдельных выражений, а также порядок, в котором имеют место побочные эффекты, не определены.

так что даже если вы спрашивали ли bar()будет работать , прежде чем baz()в foo(bar() + baz())порядок до сих пор не определен.

Даниэль Треббиен
источник
4
Пример «особого примечания» из [5.14] Логический оператор И: «В отличие от этого &, &&гарантирует оценку слева направо: второй операнд не оценивается, если первый операнд false
Даниэль Треббиен
20

Нет определенного порядка для bar () и baz () - единственное, что говорит Стандарт, это то, что они оба будут оценены до вызова foo (). Из стандарта C ++, раздел 5.2.2 / 8:

Порядок оценки аргументов не указан.


источник
4
Тот факт, что они оцениваются до foo (), по крайней мере, немного обнадеживает.
Билл
1
@BillKotsias Стандарт также говорит, что вызовы функций не могут перекрываться (т. Е. Реализация не может запускать строку 1 bar, затем строку 1 baz, затем строку 2 barи т. Д.), Что тоже хорошо. :-)
melpomene
3

В C ++ 11 соответствующий текст можно найти в 8.3.6 Аргументы по умолчанию / 9 (выделено мной)

Аргументы по умолчанию оцениваются каждый раз при вызове функции. Порядок оценки аргументов функции не указан . Следовательно, параметры функции не должны использоваться в аргументе по умолчанию, даже если они не оцениваются.

Такое же словоблудие используется и в стандарте C ++ 14, и его можно найти в том же разделе .

Р Саху
источник
0

Как уже отмечали другие, стандарт не дает никаких указаний по порядку оценки для этого конкретного сценария. Затем этот порядок оценки остается на усмотрение компилятора, и у компилятора может быть гарантия.

Важно помнить, что стандарт C ++ - это действительно язык, инструктирующий компилятор по построению ассемблерного / машинного кода. Стандарт - это только часть уравнения. Если стандарт неоднозначен или определен конкретной реализацией, вам следует обратиться к компилятору и понять, как он переводит инструкции C ++ на настоящий машинный язык.

Итак, если порядок оценки является требованием или, по крайней мере, важным, и совместимость с кросс-компилятором не является требованием, исследуйте, как ваш компилятор в конечном итоге объединит это воедино, и ваш ответ может в конечном итоге быть там. Обратите внимание, что компилятор может изменить свою методологию в будущем.

Эрудит-программист
источник