Pregunta

Hay un "muy malo" que puede suceder &&= y ||= se utiliza como azúcar sintáctico para bool foo = foo && bar y bool foo = foo || bar?

¿Fue útil?

Solución

A bool sólo podrá ser true o false en C ++. Como tal, el uso de &= y |= es relativamente seguro (a pesar de que particularmente no como la notación). Es cierto, que llevará a cabo operaciones de bits en lugar de las operaciones lógicas (y por lo tanto no lo harán cortocircuito) pero estas operaciones de bits seguir un mapeo bien definida, que es efectivamente equivalente a las operaciones lógicas, siempre como ambos operandos son de tipo bool . 1

Al contrario de lo que otras personas han dicho aquí, un bool en C ++ no debe tener un valor diferente, como 2. Al asignar dicho valor a un bool, se convierte en true según el estándar.

La única manera de conseguir un valor no válido en una bool es mediante el uso de punteros reinterpret_cast:

int i = 2;
bool b = *reinterpret_cast<bool*>(&i);
b |= true; // MAY yield 3 (but doesn’t on my PC!)

Sin embargo, puesto que este código da como resultado un comportamiento indefinido de todos modos, podemos ignorar este problema potencial en la conformación de código C ++.


1 Es cierto que esta es una gran advertencia y no como ilustra el comentario de Angew:

bool b = true;
b &= 2; // yields `false`.

La razón es que b & 2 realiza promoción número entero tal que la expresión es entonces equivalente a static_cast<int>(b) & 2, lo que resulta en 0, que luego se convierte de nuevo en un bool. Así que es cierto que la existencia de un operator &&= mejoraría la seguridad de tipos.

Otros consejos

&& y & tienen semánticas diferentes: && no evaluará el segundo operando si el primer operando es false. es decir, algo así como

flag = (ptr != NULL) && (ptr->member > 3);

es seguro, pero

flag = (ptr != NULL) & (ptr->member > 3);

no es, aunque ambos operandos son de tipo bool.

Lo mismo es cierto para &= y |=:

flag = CheckFileExists();
flag = flag && CheckFileReadable();
flag = flag && CheckFileContents();

se comportará de manera diferente que:

flag = CheckFileExists();
flag &= CheckFileReadable();
flag &= CheckFileContents();

Respuesta corta

Todos los operadores +=, -=, *=, /=, &=, |=...son la aritmética y proporcionar la misma expectativa:

x &= foo()  // We expect foo() be called whatever the value of x

Sin embargo, los operadores de &&= y ||= sería lógico, y estos operadores pueden ser propensos a errores, debido a que muchos desarrolladores de esperar foo() ser llamado siempre en x &&= foo().

bool x;
// ...
x &&= foo();           // Many developers might be confused
x = x && foo();        // Still confusing but correct
x = x ? foo() : x;     // Understandable
x = x ? foo() : false; // Understandable
if (x) x = foo();      // Obvious
  • ¿Realmente necesitamos para hacer C/C++ aún más complejo para obtener un acceso directo para x = x && foo()?

  • ¿De verdad queremos ocultar más la críptica declaración x = x && foo()?
    O queremos escribir significativas código como if (x) x = foo();?


Respuesta larga

Ejemplo para &&=

Si &&= operador estaba disponible, entonces este código:

bool ok = true; //becomes false when at least a function returns false
ok &&= f1();
ok &&= f2(); //we may expect f2() is called whatever the f1() returned value

es equivalente a:

bool ok = true;
if (ok) ok = f1();
if (ok) ok = f2(); //f2() is called only when f1() returns true

Este primer código es propenso a errores debido a que muchos desarrolladores les creo f2() es que siempre se llama a lo que el f1() valor devuelto.Es como la escritura de bool ok = f1() && f2(); donde f2() se llama sólo cuando f1() devuelve true.

  • Si el desarrollador quiere f2() se llama sólo cuando f1() devuelve true, por lo tanto el segundo código de arriba es menos propenso a errores.
  • Otra cosa (el desarrollador quiere f2() para ser llamado siempre), &= es suficiente:

Ejemplo para &=

bool ok = true;
ok &= f1();
ok &= f2(); //f2() always called whatever the f1() returned value

Además, es más fácil para el compilador para optimizar este código de arriba que por debajo de uno:

bool ok = true;
if (!f1())  ok = false;
if (!f2())  ok = false;  //f2() always called

Comparar && y &

Podemos preguntarnos si los operadores && y & dan el mismo resultado cuando se aplica en bool los valores?

Vamos a comprobar mediante el siguiente código C++:

#include <iostream>

void test (int testnumber, bool a, bool b)
{
   std::cout << testnumber <<") a="<< a <<" and b="<< b <<"\n"
                "a && b = "<< (a && b)  <<"\n"
                "a &  b = "<< (a &  b)  <<"\n"
                "======================"  "\n";
}

int main ()
{
    test (1, true,  true);
    test (2, true,  false);
    test (3, false, false);
    test (4, false, true);
}

Salida:

1) a=1 and b=1
a && b = 1
a &  b = 1
======================
2) a=1 and b=0
a && b = 0
a &  b = 0
======================
3) a=0 and b=0
a && b = 0
a &  b = 0
======================
4) a=0 and b=1
a && b = 0
a &  b = 0
======================

Conclusión

Por lo tanto se puede sustituir && por & para bool valores ;-)
Para un mejor uso &= en lugar de &&=.
Podemos considerar &&= como inútiles para los booleanos.

Mismo para ||=

operador |= también es menos propenso a errores de ||=

Si un desarrollador quiere f2() se llama sólo cuando f1() devuelve false, en lugar de:

bool ok = false;
ok ||= f1();
ok ||= f2(); //f2() is called only when f1() returns false
ok ||= f3(); //f3() is called only when f1() or f2() return false
ok ||= f4(); //f4() is called only when ...

Te recomiendo el siguiente más comprensible alternativa:

bool ok = false;
if (!ok) ok = f1();
if (!ok) ok = f2();
if (!ok) ok = f3();
if (!ok) ok = f4();
// no comment required here (code is enough understandable)

o si lo prefieres todo en una línea estilo:

// this comment is required to explain to developers that 
// f2() is called only when f1() returns false, and so on...
bool ok = f1() || f2() || f3() || f4();
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top