Pre-C ++ 17, this behavior is undefined:
Here's a quote that proves that the entire score needed to call a function and its associated side effects is sequenced before the function is called.
In addition, all other estimates that do not have a specific sequence are indefinitely sequenced. This does not impose any restrictions on the ordering of the subexpressions evaluated, although with respect to each other, they remain inconsistent with respect to each other.
1.9 Execution of the program ยง 15
Except where noted, evaluations of the operands of individual operators and subexpressions of individual expressions are not affected. [...]
The calculation of the values โโof the operands of the operator is sequenced before calculating the value of the result of the operator. If the side effect of the scalar object does not affect any other effect on the same scalar object or the calculation of the value using the value of the same scalar object, the behavior is undefined.
When a function is called (regardless of whether the function is built-in), each value calculation and side effect associated with any argument expression, or with the postfix expression representing the called function, are sequenced before each expression or statement in the body of the called function.
[Note. Value calculations and side effects associated with different argument expressions have no meaning. -end note]
Each estimate in the calling function (including other function calls), which otherwise is not secreted separately before or after the body of the called function is executed, is indefinitely ordered with respect to the execution of the called function . 9 Several contexts in C ++ cause an evaluation of a function call, even if the syntax of the corresponding functions is not displayed in the translation block. . [...]
The sequence constraints for executing the called function (as described above) are function call functions that are evaluated, regardless of the syntax of the expression that calls the function.
Other relevant quotes relate to std::move
template typename remove_reference :: type && & move (T & t) noexcept;
Returns: static_cast <typename remove_reference :: type &> (t).
And std::unique_ptr<T>.operator->() :
20.7.1.2.4 unique_ptr observers
pointer operator โ () const noexcept;
Requires: get ()! = Nullptr.
Returns: get ().
memfunc gets its argument by value, so we have 3 calls:
a) obj->memfunc b) std::move(obj)
c) the constructor for moving the argument passed.
Since b) does not change anything, we can ignore it for the argument:
a and c are indefinitely sequenced, so either they can be in front of another.
If the first one happens, everything is fine; c changing obj doesn't matter.
If c occurs first, a is evaluated with zero obj , violating the precondition, so we have UB.
So this is undefined Behavior, because one of the allowed orders has undefined behavior.
Post-C ++ 17, it is defined correctly:
8.2.2 Function call [expr.call]
1 A function call is a postfix expression, followed by parentheses containing possibly empty comma-separated lists of initializers that make up the arguments to the function. [...]
[...]
5 A post-simulation is sequenced before each expression in the expression list and any default argument. [...]
[...]