Domanda

C'è una "cosa molto brutta" che può accadere && = e || = sono state usate come sintattica zucchero per bool foo = foo && bar e bool foo = foo || bar?

È stato utile?

Soluzione

Un bool può essere true o false in C ++ solo. Come tale, utilizzando &= e |= è relativamente sicuro (anche se non mi piace particolarmente la notazione). Vero, si esibiranno operazioni bit anziché operazioni logiche (e quindi non si corto circuito), ma queste operazioni bit seguire una mappatura ben definito, che è effettivamente equivalente alle operazioni logiche, fintanto il entrambi gli operandi sono di tipo bool . 1

Al contrario di quello che altre persone hanno detto qui, un bool in C ++ non deve mai avere un valore diverso, ad esempio 2. Quando si assegna il valore a un bool, esso verrà convertito in true alla norma.

L'unico modo per ottenere un valore non valido in una bool è quello di utilizzare reinterpret_cast su puntatori:

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

Ma poiché questo risultato codice di comportamento non definito in ogni caso, si può ignorare questo potenziale problema in conformità del codice C ++.


1 Certo questo è un avvertimento piuttosto grande come il commento di Angew illustra:

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

Il motivo è che b & 2 esegue promozione intero tale che l'espressione è quindi equivalente alla static_cast<int>(b) & 2, che si traduce in 0, che viene poi riconvertito in un bool. Allora è vero che l'esistenza di un operator &&= migliorerebbe la sicurezza tipo.

Altri suggerimenti

&& e & hanno diverse semantiche: && non valuterà il secondo operando se il primo operando è false. vale a dire una cosa del genere

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

è sicuro, ma

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

non è, anche se entrambi gli operandi sono di tipo bool.

Lo stesso vale per &= e |=:

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

si comporterà in modo diverso rispetto:

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

Risposta breve

Tutti gli operatori +=, -=, *=, /=, &=, |= ... sono aritmetica e fornire stessa aspettativa:

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

Tuttavia, gli operatori &&= e ||= sarebbe logico, e questi operatori potrebbero essere soggette a errori, perché molti sviluppatori si aspettano foo() sempre essere chiamato in 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
  • Abbiamo davvero bisogno di fare C / C ++ ancora più complessa per ottenere una scorciatoia per x = x && foo()?

  • Vogliamo davvero di offuscare più il x = x && foo() dichiarazione criptica?
    O vogliamo scrivere codice significativo come if (x) x = foo();?


Risposta lunga

Esempio per &&=

Se operatore &&= era disponibile, allora questo codice:

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

è equivalente a:

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

Questo primo codice è soggette a errori perché molti sviluppatori potrebbe pensare f2() viene sempre chiamato qualunque sia il f1() restituito il valore. E 'come scrivere bool ok = f1() && f2(); dove f2() viene chiamato solo quando f1() ritorna true.

  • Se lo sviluppatore in realtà vuole f2() di essere chiamato solo quando f1() ritorna true, quindi, il secondo codice di cui sopra è meno soggetto a errori.
  • Else (lo sviluppatore vuole f2() essere sempre chiamato), &= è sufficiente:

Esempio per &=

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

Inoltre, è più facile per il compilatore per ottimizzare il codice di cui sopra di quello di sotto di un:

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

Confronta && e &

Ci si può chiedere se gli operatori && e & danno lo stesso risultato se applicato su valori bool?

assegno Let utilizzando il seguente codice 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);
}

Output:

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
======================

Conclusione

Quindi YES possiamo sostituire && da & per i valori bool ;-)
Quindi, un uso migliore &= invece di &&=.
Possiamo considerare &&= come inutile per booleani.

Stesse per ||=

  

operatore |= è anche meno error-prone di ||=

Se uno sviluppatore vuole f2() essere chiamato solo quando f1() ritorna false, invece di:

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

I consigli la seguente alternativa più comprensibile:

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, se preferite il tutto in una sola riga stile:

// 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();
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top