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".