>The following code swaps values between 2 variables without using a temp variable.....
Actually, it invokes undefined behavior and could really do anything. If you add sequence points between the operations, then the code is technically correct:

a ^= b;
b ^= a;
a ^= b;

Figure out the bit value for a and b, then work it out yourself using the truth table for XOR:

End result, a == 0101 and b == 1010, which is an inversion of the original state. The XOR swap is an archaic trick to avoid the need for a temporary variable. It's still relevant if you're writing assembly or on a severely memory constrained platform, but for the most part not recommended because

As you've proven, it's not as obvious what's going on.

Tricks like this can actually hinder a compiler's optimizer, resulting in less efficient machine code.

It doesn't always work. For example, if you XOR an object with itself, the result is 0 rather than the expected unchanged value. When a common implementation uses pointers, it's not an unexpected situation and needs a special case (which further complicates and slows things down):

template <typename T>
void swap(T& a, T& b)
{
if (&a != &b) {
a ^= b;
b ^= a;
a ^= b;
}
}

>The following code swaps values between 2 variables without using a temp variable.....
Actually, it invokes undefined behavior and could really do anything. If you add sequence points between the operations, then the code is technically correct:

a ^= b;
b ^= a;
a ^= b;

Figure out the bit value for a and b, then work it out yourself using the truth table for XOR:

End result, a == 0101 and b == 1010, which is an inversion of the original state. The XOR swap is an archaic trick to avoid the need for a temporary variable. It's still relevant if you're writing assembly or on a severely memory constrained platform, but for the most part not recommended because

As you've proven, it's not as obvious what's going on.

Tricks like this can actually hinder a compiler's optimizer, resulting in less efficient machine code.

It doesn't always work. For example, if you XOR an object with itself, the result is 0 rather than the expected unchanged value. When a common implementation uses pointers, it's not an unexpected situation and needs a special case (which further complicates and slows things down):

template <typename T>
void swap(T& a, T& b)
{
if (&a != &b) {
a ^= b;
b ^= a;
a ^= b;
}
}

thank you very much Narue for the detailed explanation