Suppose I have the following function:
void foo(std::vector<int> vec, int n);
If I call the function like this:
std::vector<int> numbers { 2, 3, 5, 7, 11, 13, 17, 19 };
foo(std::move(numbers), numbers[0]);
Are all the arguments completely evaluated before being bound to their parameters? In that case, the std::move
is harmless, because it simply yields an xvalue referring to numbers
. Or can each individual argument immediately be bound to its parameter as soon as it is evaluated? In that case, numbers[0]
could cause undefined behavior, because numbers
could already have been moved into vec
.
Note the difference between parameters and arguments: Function parameters are the names listed in the function's definition. Function arguments are the real values passed to the function. Parameters are initialized to the values of the arguments supplied.
Arguments are passed by value; that is, when a function is called, the parameter receives a copy of the argument's value, not its address. This rule applies to all scalar values, structures, and unions passed as arguments. Modifying a parameter does not modify the corresponding argument passed by the function call.
When you pass an argument by reference, you pass a pointer to the value in memory. The function operates on the argument. When a function changes the value of an argument passed by reference, the original value changes. When you pass an argument by value, you pass a copy of the value in memory.
A parameter is a variable in the declaration of the function. An argument is the actual value of the variable that gets passed to the function.
On §1.9/15 we're told that:
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. (...)
And on §5.2.2/4:
(...) The initialization and destruction of each parameter occurs within the context of the calling function. (...)
I couldn't find any other relevant text in the final draft. Since this does not explicitly define a sequenced before relationship between evaluation of arguments and the initialization of the parameters, they're unsequenced and the std::move
is not harmless.
A solution to this issue would be to force a sequence with a temporary variable:
std::vector<int> numbers { 2, 3, 5, 7, 11, 13, 17, 19 };
int num = numbers[0];
foo(std::move(numbers), num);
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