c++ c swap order-of-evaluation

c++ - Problema potencial en "Intercambiar valores de dos variables sin usar una tercera variable"



swap order-of-evaluation (8)

Recientemente vine a lo largo de este método para intercambiar los valores de dos variables sin usar una tercera variable.

a^=b^=a^=b

Pero cuando probé el código anterior en diferentes compiladores, obtuve resultados diferentes, algunos dieron resultados correctos y otros no.

¿Hay algo terriblemente mal con el código?


¿Hay algo terriblemente mal con el código?

¡Sí!

a^=b^=a^=b invoca de hecho el comportamiento indefinido en C y en C ++ porque está intentando cambiar el valor de a más de una vez entre dos puntos de secuencia.

Intenta escribir (aunque no infalible)

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

en lugar de a^=b^=a^=b .

PD : nunca intente intercambiar los valores de dos variables sin utilizar una tercera. Siempre use una tercera variable.

EDITAR :

Como @caf notó que b^=a^=b está bien aunque el orden de evaluación de los argumentos de ^= operator no esté especificado, ya que todos los accesos de b dentro de la expresión se están utilizando para calcular el valor final que se está almacenando en b , el comportamiento está bien definido.


¿Qué hay de este?

a = a + b; b = a - b; a = a - b;


Hazlo asi:

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


Le sugiero que use std :: swap () para c ++.

Para c, usa esta macro. Tenga en cuenta que primero debe comparar ayb, de lo contrario, cuando apunten a la misma ubicación de memoria, borrará el valor y se convertirá en 0.

#define swap(a, b) ((a) == (b) || (a) ^= (b), (b) ^= (a), (a) ^= (b))


Me pregunté por qué nadie sugirió paréntesis de la expresión. Parece que ya no es UB.

a^=(b^=(a^=b));


Si está utilizando C ++, ¿por qué no usa el algoritmo de intercambio en STL? Es ideal para este propósito y está muy claro lo que hace:

#include <algorithm> using namespace std; // ... int x=5, y=10; // x:5 y:10 swap(x,y); // x:10 y:5


También puede probar el siguiente, pero si los números son lo suficientemente grandes, el valor se desbordará

a=a*b; b=a/b; a=a/b;


Basado en contribuciones de R. & sellibitze:

Utilice el operador de coma:

(a^=b,b^=a,a^=b);

De texto y Wikipedia:

"El operador de coma se puede utilizar para vincular las expresiones relacionadas entre sí. Una lista de expresiones vinculadas con comas se evalúa de izquierda a derecha y el valor de la expresión más a la derecha es el valor de la expresión combinada. Actúa como un punto de secuencia. "

"Un punto de secuencia garantiza que todos los efectos secundarios de evaluaciones anteriores se habrán realizado, y aún no se han realizado efectos secundarios de evaluaciones subsiguientes. Se elimina el comportamiento indefinido que surge del orden de ejecución poco claro de la expresión original".