views:

167

answers:

4
A: 

It's often more of a danger (in your case it's actually undefined behavior; plus if one number is zero, things go wrong). Unless you're cripplingly low on memory, it's better to just use a temp variable (or the stl swap function). This is more clear about what you're doing and easier to maintain.

JoshD
+5  A: 

the way you have written it, it is undefined behavior. This is because you are modifying a variable more than once in the same sequence point. However if you rewrite it as follows:

m ^= n;
n ^= m;
m ^= n;

then it is safe. However, "useful" is another question, it is rarely "useful" and sometimes it is actually slower than actually using a temp!

Also you need to be careful with aliasing (pointers/references) because if you try to swap something with itself, then you end up accidentally zeroing your value. For example:

#define SWAP(m, n) { m ^= n; n ^= m; m ^= n; }

int x[] = { 1, 2, 3, 4 };
int i = 0;
int j = 0;
SWAP(x[i], x[j]); // whoops, x[0] == 0 now, not 1!

a more traditional swap implementation doesn't have this issue.

Evan Teran
+3  A: 

No, it is undefined behaviour in both C and C++. It may work sometimes, but you should not rely on it.

Also even the "fixed" variation doesn't always work:

m ^= n;
n ^= m;
m ^= n;

This fails if m and n are references to the same variable. In this case it sets the value to zero.

C doesn't have references but even in C there are still dangers lurking if you try to use this trick:

  • You may try to put the "working" version into a macro SWAP, but that can fail if called with SWAP(x, x), setting x always to zero.
  • You may try to extend the trick to swapping two values in an array, but again this can fail if you use the same index:

    a[m] ^= a[n];
    a[n] ^= a[m];
    a[m] ^= a[n];
    

Now if m == n again the value of a[m] is set to zero.

Please don't use "clever" tricks like this. Use a temporary variable to swap two values.

Mark Byers
+1  A: 

with that trick, you save an extra memory location to save a temporary value. It may be efficiant for integers, but is that readable ? Your last generation optimizer may do the same.

Marc
Modern CPU's do better with a temporary. They can execute the two assignments in parallel, but they must stall for the XOR version.
GMan
@GMan: you mean instruction pairing? But which assignments can be paired in this case?
Nick D
@Nick: With `int temp = x; x = y; y = temp;`, the latter two.
GMan
@GMan: doesn't `y` add a dependency between the 2 instructions? Thus, no pairing due to a read after being written. The same also applies to the first 2 instructions, unless I'm missing something :)
Nick D
@GMan: yep, those last two can be paired :) I guess `mov x, y;` is a typo. It should be `mov x reg1;`.
Nick D
@Nick: In psuedo-assembly: `mov reg0, x; mov reg1, y; mov x, reg1; mov y, reg0;`. Two cycles does four-moves, two each. EDIT: I ninja'd you, sorry. :)
GMan