I recently ran across the following situation:
#include <iostream>
int *p = 0;
int f() {
p = new int(10);
return 0;
}
void g(int x, int *y = p) {
std::cout << y << std::endl;
}
int main() {
g(f());
}
This is quite subtle, since you usually don't expect the default arguments to change during their evaluation for the function call. I had to take a look at the assembly to spot this error.
Now my question is: Is this really undefined behavior, since there aren't any guarantees concerning the evaluation order of function arguments?
Yes, it matters. The arguments must be given in the order the function expects them. C passes arguments by value. It has no way of associating a value with an argument other than by position.
The order of evaluation of function arguments is unspecified. Consequently, parameters of a function shall not be used in a default argument, even if they are not evaluated. The same verbiage is used by C++14 standard as well, and is found under the same section.
3. Positional Arguments. During a function call, values passed through arguments should be in the order of parameters in the function definition. This is called positional arguments.
Order of evaluation refers to the operator precedence and associativity rules according to which mathematical expressions are evaluated.
The order of evaluation (i.e. determining the value) of function arguments is not specified. The compiler is free to execute them in any order, and even intermingled if there are no other factors stopping it from doing so.
Evaluation of default arguments happens in the context of the caller, not the callee. So the call to f() is necessary for one argument, and reading the global variable p for the other. Which order this happens in is not specified, so the global could be read before or after the call to f().
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