With C++11, is it undefined behavior to write f(x++), g(x++)?

I was reading this question:

Undefined behavior and sequence points

and, specifically, the C++11 answer, and I understand the idea of "sequencing" of evaluations. But - is there sufficient sequencing when I write:

f(x++), g(x++); ?

That is, am I guaranteed that f() gets the original value of x and g() gets a once-incremented x?

Notes for nitpickers:

  • Assume that operator++() has defined behavior (even if we've overriden it) and so do f() and g(), that no exceptions will be thrown, etc. - this question is not about that.
  • Assume that operator,() has not been overloaded.

Answers


No, the behavior is defined. To quote C++11 (n3337) [expr.comma/1]:

A pair of expressions separated by a comma is evaluated left-to-right; the left expression is a discarded-value expression (Clause [expr]). Every value computation and side effect associated with the left expression is sequenced before every value computation and side effect associated with the right expression.

And I take "every" to mean "every"1. The evaluation of the second x++ cannot happen before the call sequence to f is completed and f returns.2


1 Destructor calls aren't associated with sub-expressions, only with full expressions. So you'll see those executed in reverse order to temporary object creation at the end of the full expression. 2 This paragraph only applies to the comma when used as an operator. When the comma has a special meaning (such when designating a function call argument sequence) this does not apply.


No, it isn't undefined behavior.

According to this evaluation order and sequencing reference the left hand side of the comma is fully evaluated before the right hand side (see rule 9):

9) Every value computation and side effect of the first (left) argument of the built-in comma operator , is sequenced before every value computation and side effect of the second (right) argument.

That means an expression like f(x++), g(x++) is not undefined.

Note that this is only valid for the built-in comma operator.


It depends.

First, let's assume that x++ by itself does not invoke undefined behavior. Think about signed overflow, incrementing a past-the-end-pointer, or the postfix-increment-operator might be user-defined). Further, let's assume that invoking f() and g() with their arguments and destroying the temporaries does not invoke undefined behavior. That are quite a lot of assumptions, but if they are broken the answer is trivial.

Now, if the comma is the built-in comma-operator, the comma in a braced-init-list, or the comma in a mem-initializer-list, the left and right side are sequenced either before or after each other (and you know which), so don't interfere, making the behavior well-defined.

struct X {
    int f, g;
    explicit X(int x) : f(x++), g(x++) {}
};
// Demonstrate that the order depends on member-order, not initializer-order:
struct Y {
    int g, f;
    explicit Y(int x) : f(x++), g(x++) {}
};
int y[] = { f(x++), g(x++) };

Otherwise, if x++ invokes a user-defined operator-overload for postfix-increment, you have indeterminate sequencing of the two instances of x++ and thus unspecified behavior.

std::list<int> list{1,2,3,4,5,6,7};
auto x = begin(list);
using T = decltype(x);

void h(T, T);
h(f(x++), g(x++));
struct X {
    X(T, T) {}
}
X(f(x++), g(x++));

And in the final case, you get full-blown undefined behavior as the two postfix-increments of x are unsequenced.

int x = 0;

void h(int, int);
h(f(x++), g(x++));
struct X {
    X(int, int) {}
}
X(f(x++), g(x++));

Need Your Help

Xcode : warning: directory not found for option

xcode ios5 linker linker-errors

Ld /Users/pwang/Library/Developer/Xcode/DerivedData/socketiohldwxnslzhlnjtgihgewdwavpjpb/Build/Products/Debug-iphoneos/socketio.app/socketio normal armv7

Detect if content of EditText was changed by user or programmatically?

android listview android-edittext textwatcher

I would need a way to detect if the EditText has been changed by the user typing something or by the app changing the text programmatically. Any standard way of doing this? I guess I could always do