Подтвердить что ты не робот

В f (x), x может быть оценена до f?

У меня есть программа на С++. Эта программа делает что-то вроде этого:

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

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

4b9b3361

Ответ 1

Pre-С++ 17, это поведение undefined:

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

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

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

Другие релевантные цитаты относятся к std::move

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

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

20.7.1.2.4 unique_ptr наблюдатели

оператор указателя → () const noexcept;
Требуется: get()!= Nullptr.
Возвращает: get().

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

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

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

Post-С++ 17, он определен корректно:

8.2.2 Вызов функции [expr.call]

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

Ответ 2

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

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

(С++ 11, § 5.2.2/8)