6

I still could not clearly understand whether the expression x ^= y ^= x ^= y; valid in C++11 (as they say in this thread) or it leads to undefined behavior?

The reasons given by the link seem convincing, but clang throws a warning:

warning: unsequenced modification and access to 'x' [-Wunsequenced]

Moreover, if both versions:

x ^= y ^= x ^= y; // (1) 
x = x ^ (y = y ^ (x = (x ^ y))); // (2)

considered equivalent (and well-defined in C++11), why it gives different results (first, second)?

Additionally, it should be noted that the gcc gives a warning about sequence point only on the second version of code.

Community
  • 1
  • 1
αλεχολυτ
  • 4,792
  • 1
  • 35
  • 71
  • 2
    No, it isn't well-defined. The analysis is very similar to that of `i += ++i + 1` in [this question](http://stackoverflow.com/questions/24194076/in-c11-does-i-i-1-exhibit-undefined-behavior). – T.C. Mar 28 '15 at 08:34
  • those versions are not equivatent at all. – UmNyobe Mar 28 '15 at 08:53
  • 1
    See http://stackoverflow.com/questions/29313902/sequence-point-within-assignment-operators – Lingxi Mar 28 '15 at 09:13
  • 3
    May I make a suggestion for your sanity? Stop wasting your time thinking about stuff like this. Whatever the true answer is, knowing it will not improve your life as a programmer in any way whatsoever. – Benjamin Lindley Mar 28 '15 at 09:41
  • 2
    @BenjaminLindley I'm pretty sure knowing about UB and pitfalls introducing it is of vital importance. – Columbo Mar 28 '15 at 09:50
  • 6
    @Columbo: Sure it is, in general. But not in this particular case. In this particular case all you need to know is that this is a stupid way to write code, so don't do it. Then the issue of whether it is UB or not is irrelevant. – Benjamin Lindley Mar 28 '15 at 09:51
  • `std::swap(x, y)` *IS* defined, shorter, and easier to read, so who cares? – Bo Persson Mar 28 '15 at 17:13
  • 1
    @BenjaminLindley Of course, I agree that most programmers can be more appropriate not to dive into some of the subtleties of the standard, and use very obvious options such as swap. However, questions marked by the tag "language-lawyer" just mean the desire to understand these subtleties. – αλεχολυτ Mar 28 '15 at 19:36
  • 1
    @BenjaminLindley What? If someone asks you to explain why a particular snippet of code invokes undefined behavior, you explain it to him, rather than responding "That's just stupid, you know. Don't do it. Now back to work". People learn about fundamental rules of the language by understanding why this is not allowed, and that's not a waste of time. – Columbo Apr 01 '15 at 17:39

1 Answers1

11

The assignment operator (=) and the compound assignment operators all group right-to-left. [..]
The behavior of an expression of the form E1 op = E2 is equivalent to E1 = E1 op E2 except that E1 is evaluated only once.

Thus your code is equivalent to

x = x ^ (y ^= (x ^= y)));

... with x evaluated only once in x = x .... Unfortunately, for xor's, the evaluation of the operands is unsequenced. I.e.

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.

applies. But now we have a problem:

   x = x ^ (y ^= (x ^= y)));
//     *          ******
//     |            |
//     |            Side effect
//     Value computation

The value computation (which is implied in the singular evaluation of x for the two leftmost x) and the side effect are unsequenced wrt each other, hence we induce UB:

If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.

Columbo
  • 60,038
  • 8
  • 155
  • 203