sobrecarga operator bitwise c++ boolean-operations

bitwise - operator[] c++



¿Por qué c++ no tiene &&=o ||=para booleanos? (3)

¿Hay algo "muy malo" que pueda suceder? && = y || = se usaron como azúcar sintáctico para bool foo = foo && bar y bool foo = foo || bar bool foo = foo || bar ?


Respuesta corta

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

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

Sin embargo, los operadores &&= y ||= serían lógicos, y estos operadores podrían ser propensos a errores porque muchos desarrolladores esperarían que foo() siempre se llamara 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 hacer que C / C ++ sea aún más complejo para obtener un atajo para x = x && foo() ?

  • ¿Realmente queremos ofuscar más la declaración críptica x = x && foo() ?
    O queremos escribir un código significativo como if (x) x = foo(); ?

Respuesta larga

Ejemplo para &&=

Si &&= operator 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 pensarían que f2() siempre se llama sea cual sea el valor devuelto f1() . Es como escribir bool ok = f1() && f2(); donde f2() se invoca solo cuando f1() devuelve true .

  • Si el desarrollador realmente desea que se llame a f2() solo cuando f1() devuelve true , por lo tanto, el segundo código anterior es menos propenso a errores.
  • De lo contrario (el desarrollador quiere que siempre se llame a f2() ), &= 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 optimizar este código anterior que el siguiente:

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

Compara && y

Podemos preguntarnos si los operadores && y & dan el mismo resultado cuando se aplican a los valores de bool ?

Vamos a verificar usando el siguiente código de 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, , podemos reemplazar && por & para valores bool ;-)
Así que es mejor usar &= lugar de &&= .
Podemos considerar &&= como inútil para los booleanos.

Lo mismo para ||=

operator |= también es menos propenso a errores que ||=

Si un desarrollador quiere que f2() se invoque solo 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 ...

Aconsejo la siguiente alternativa más comprensible:

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 prefieres todo en un estilo de línea :

// 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();


Un bool solo puede ser true o false en C ++. Como tal, usar &= y |= es perfectamente seguro (aunque no me gusta particularmente la notación). Es cierto que realizarán operaciones de bits en lugar de operaciones lógicas (y por lo tanto no provocarán un cortocircuito), pero estas operaciones de bits siguen una asignación bien definida, que es efectivamente equivalente a las operaciones lógicas, siempre que ambos operandos sean de tipo bool . 1

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

La única forma de obtener un valor no válido en un bool es mediante el uso de reinterpret_cast en los punteros:

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

Pero dado que este código da como resultado un comportamiento indefinido de todos modos, podemos ignorar con seguridad este posible problema al conformar el código C ++.

1 Es cierto que esta es una advertencia bastante grande como ilustra el comentario de Angew:

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

La razón es que b & 2 realiza la promoción de enteros de modo que la expresión es equivalente a static_cast<int>(b) & 2 , que da como resultado 0 , que luego se convierte nuevamente en un bool . Entonces, es cierto que la existencia de un operator &&= mejoraría la seguridad del tipo.


&& y & tienen una semántica diferente: && 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 lo 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 a:

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