В f (x) можно ли вычислить x до f?


у меня есть программа на языке C++. Эта программа делает что-то вроде этого:

struct MyT {void memfunc(std::unique_ptr<MyT> arg);};
std::unique_ptr<MyT> obj = /* some init */;
obj->memfunc(std::move(obj));

это гарантированно будет действительным, или я могу в конечном итоге вызвать функцию-член на nullptr?
Стандартные котировки применимы.
Я знаю, что порядок оценки аргументов не имеет последовательности, но я не помню, что такое последовательность, т. е. вызываемый объект функции.

2 52

2 ответа:

Pre-C++17, это неопределенное поведение:

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

1.9 выполнение программы § 15

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

другие соответствующие цитаты о std::move

template typename remove_reference:: type&& move(T & & t) noexcept;
Возвращается: static_cast(t).

и std::unique_ptr<T>.operator->():

20.7.1.2.4 наблюдателей объекта unique_ptr

оператор указателя - > () const noexcept;
Требуется: получить() != nullptr.
Возвращает: получить().

memfunc возвращает свой аргумент по значению, поэтому у нас есть 3 звонки:
а) obj->memfunc б) std::move(obj)
c) конструктор перемещения переданного аргумента.
Потому что б) не меняется все, что угодно, мы можем игнорировать его для аргумента:

a и c неопределенно упорядочены, поэтому любой из них может быть перед другим.
Если это произойдет, во-первых, все хорошо, с изменением obj не имеет значения.
Если С происходит, во-первых, оценивается с обнуляться obj, нарушая предварительное условие, поэтому у нас есть UB.

таким образом, это неопределенное поведение, потому что один из разрешенных ордеров имеет неопределенное поведение.

Post-C++17, это четко определено:

8.2.2 вызов функции [expr.звоните]

1 вызов функции-это постфиксное выражение, за которым следуют круглые скобки, содержащие возможно пустой, разделенный запятыми список инициализатор-п. которые составляют аргументы функции. [...]
[...]
5 The постфиксное-выражение расположено перед каждой выражение на expression-list и любой аргумент по умолчанию. [...]
[...]

Да, оценка x может происходить до, после или во время оценки f (они без последовательности).

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

(C++11, §5.2.2/8)