I have a C++ program. This program does something like this:
struct MyT {void memfunc(std::unique_ptr<MyT> arg);}; std::unique_ptr<MyT> obj = /* some init */; obj->memfunc(std::move(obj));
Is this guaranteed to be valid, or can I end up calling a member function on nullptr
?
Standard quotes applicable.
I know that the order of evaluation of the arguments is unsequenced, but I don't recall what the sequencing is w.r.t. the function object being called.
Evaluating a function means finding the value of f(x) =… or y =… that corresponds to a given value of x. To do this, simply replace all the x variables with whatever x has been assigned. For example, if we are asked to evaluate f(4), then x has been assigned the value of 4.
To evaluate a function, substitute the input (the given number or expression) for the function's variable (place holder, x). Replace the x with the number or expression. 1. Given the function f (x) = 3x - 5, find f (4).
Here the quote which proves that all evaluation neccessary to call a function and associated side-effects are sequenced before the function call.
Also, all other evaluations not specifically sequenced are indeterminately sequenced.
That does not impose any ordering constraints on the sub-expressions evaluated though with respect to each other, they remain unsequenced with respect to each other.
1.9 Program execution § 15
Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.
[...]
The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. If a side effect on a scalar object is unsequenced relative to either anotherside effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.
When calling a function (whether or not the function is inline), every value computation and side effect associated with any argument expression, or with the postfix expression designating the called function, is sequenced before execution of every expression or statement in the body of the called function.
[ Note: Value computations and side effects associated with different argument expressions are unsequenced. —end note ]
Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function.9 Several contexts in C++ cause evaluation of a function call, even though no corresponding function call syntax appears in the translation unit. [ ... ]
The sequencing constraints on the execution of the called function (as described above) are features of the function calls as evaluated, whatever the syntax of the expression that calls the function might be.
Other relevant quotes are about 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 move constructor of the passed argument.
Because b) does not change anything, we can disregard it for the argument:
a and c are indeterminately sequenced, so either can be before the other.
If a happens first, everything is good, c changing obj
does not matter.
If c happens first, a is evaluated with a zeroed obj
, violating the precondition, so we have UB.
In summary, it is Undefined Behavior, because one of the allowed orders has undefined behavior.
8.2.2 Function call [expr.call]
1 A function call is a postfix expression followed by parentheses containing a possibly empty, comma-separated list of initializer-clauses which constitute the arguments to the function. [...]
[...]
5 The postfix-expression is sequenced before each expression in the expression-list and any default argument. [...]
[...]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With