Есть ли точка последовательности между вызовом функции, возвращающим объект, и вызовом метода на этом объекте? - программирование
Подтвердить что ты не робот

Есть ли точка последовательности между вызовом функции, возвращающим объект, и вызовом метода на этом объекте?

Если я пишу f(x)->g(args, ...), могу ли я полагаться на точку последовательности после f(x) до оценки args, ...? Я вижу аргументы в обоих направлениях:

  • §1.9.17 "При вызове функции (независимо от того, является ли функция встроенной), после оценки всех аргументов функции (если они есть) есть точка последовательности, которая выполняется перед выполнением любых выражений или операторов в body > После копирования возвращаемого значения и перед выполнением любых выражений вне функции есть также точка последовательности."
  • С другой стороны, указатель объекта неявно является скрытым аргументом this, как будто я написал g(f(x), args, ...), который предлагает его как аргумент и, следовательно, не указан.

Оператор -> не является нормальным двоичным оператором, так как ясно, что g(...) не может быть оценен до f(x), как если бы я написал f(x) + g(...). Я удивлен, что не могу найти какое-то конкретное утверждение об этом.

4b9b3361

Ответ 1

Ответ зависит от того, какую версию стандарта C++ вы используете (или ваш компилятор).

C++ 2003 5.2.2 p8 сказал:

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

Это означает, что между оценкой f(x) и args нет точки последовательности.

В C++ 2011 вся концепция точек последовательности была заменена (см. N1944), и эта формулировка теперь просто примечание:

[Примечание: оценки выражения postfix и выражений аргумента не являются последовательными по отношению друг к другу. Все побочные эффекты при оценке выражений аргументов секвенируются до входа в функцию (см. 1.9). - конец примечания]

и 1.9 p15 говорит

При вызове функции (независимо от того, является ли функция встроенной), каждое вычисление значения и побочный эффект, связанные с любым выражением аргумента или с выражением постфикса, обозначающим вызываемую функцию, упорядочиваются перед выполнением каждого выражения или оператора в теле вызываемая функция. [Примечание: вычисления значений и побочные эффекты, связанные с различными выражениями аргументов, не являются последовательными. - конец примечания]

Это говорит о том, что выражение f(x) и args выражения упорядочены перед всем в теле g, но они не упорядочены относительно друг друга, что соответствует правилам C++ 03, но сформулировано по-разному.

C++ 14 имеет те же правила, что и C++ 11, но, как отмечено в комментарии ниже, правила изменились в C++ 17.

C++ 2017 8.2.2 [expr.call] p5 говорит:

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

Для вашего примера это означает, что следующие шаги выполняются по порядку:

  • f оценивается.
  • x вычисляется и параметры f инициализируются.
  • Вызов функции f(x) оценивается.
  • f(x)->g оценивается.
  • args и другие аргументы g вычисляются, и параметры g инициализируются (в неуказанном порядке).
  • Наконец, выполняется вызов функции f(x)->g(args,...).

Ответ 2

Заметьте, я думаю, что вы задаете один вопрос в своем названии, а другой - в теле вашего вопроса.

Ну, это не совсем противоречиво. Чтобы оценить вашу функцию, должно произойти следующее (не обязательно в этом порядке).

  • x оценивается (A)
  • args оценивается (B)
  • ... оценивается (C)
  • f (x) называется (D)
  • копируется возвращаемое значение f (x) (E)
  • return- > g (args,...) называется (F)

Теперь правила, которые вы указали, показывают, что

  • (A) должно произойти до (D), так как есть точка последовательности оценки аргументов функции перед оценкой.
  • (D) происходит до (E), так как копия не может быть выполнена до тех пор, пока функция не будет выполнена.
  • (F) происходит после (E), так как неявный указатель необходим для вызова g (args) *
  • (B) и (C) происходят до (F), поскольку они являются аргументами.

Однако неясно, есть ли связь между (A), (B) и (C) или вашим вопросом между (B) и (C) и (D), поскольку они не являются аргументами ( F), впоследствии они могут быть оценены. ИЛИ, они могут быть оценены ранее.

* Интересный вопрос. Что произойдет, если g (args,...) является статической функцией-членом. В этом случае, поскольку возвращенный указатель из f (x) фактически не передается, может ли он быть секвенирован ранее? Но это отдельный вопрос.