Reputation: 385305
The following has unspecified results because evaluation order is unspecified:
std::string f() {
std::cout << "f()";
return "";
}
std::string g() {
std::cout << "g()";
return "";
}
int main() {
std::cout << f() << g();
}
// Output: "f()g()" or "g()f()".
To the best of my knowledge, though, it's not invoking undefined behaviour.
However, modifying a variable twice between sequence points is definitely UB, e.g.:
int main() {
int x = 0;
std::cout << x++ << x++;
}
Now, does that rule refer only to the current scope, or would the following also be UB?
int foo() {
static int x = 0;
x++;
return x;
}
int main() {
std::cout << foo() << foo();
}
// Output: "12" or "21", or is it undefined?
The reason I ask is that my GCC 4.7.0 20111217 doesn't warn on snippet 3, but (of course) will on snippet 2.
Upvotes: 3
Views: 335
Reputation: 16046
ISO14882:2011(e) says in 1.9-15 :
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.
So the order of foo calls is still unspecified, but certainly not UB.
Upvotes: 4
Reputation: 185988
The order of evaluation of the two calls to foo()
is unspecified. The first one called will return 1 and second will return 2, so the result will depend on the compiler's choice of evaluation order. However, since there are sequence points within foo()
, I'd guess that it isn't UB — the side-effect of x++
is guaranteed to be complete before the function returns.
Upvotes: 2
Reputation: 154017
Both calling a function and returning from a function are sequence points, so nothing you do in one function can conflict with what you do in another (even if the order in which the functions are called is unspecified).
Note that in this regard, user defined operator overloads are functions,
and introduce sequence points that wouldn't be present for built in
types. So that something like cout << i++ << i++
isn't undefined
behavior if i
is a user defined type (e.g. an enum with a user defined
operator++
). (The order is still unspecified, however, and just
because the behavior is defined doesn't mean that the code is readable
or recommendable.)
Upvotes: 8