Frage

Gibt es eine "Sehr schlechte Sache" das kann passieren && = und || = wurden als syntaktischer Zucker für verwendet bool foo = foo && bar und bool foo = foo || bar?

War es hilfreich?

Lösung

EIN bool darf nur sein true oder false in C ++. Als solche verwenden &= und |= ist relativ sicher (obwohl ich die Notation nicht besonders mag). Richtig, sie führen eher Bitoperationen als logische Operationen aus (und somit werden diese Bit-Operationen jedoch nicht definiert, was den logischen Operationen effektiv entspricht. so lange wie Beide Operanden sind vom Typ bool.1

Entgegen dem, was andere Menschen hier gesagt haben, a bool in C ++ darf niemals einen anderen Wert haben, wie z. 2. Bei der Zuweisung dieses Wertes zu a bool, es wird zu konvertiert true gemäß dem Standard.

Die einzige Möglichkeit, einen ungültigen Wert in a zu erhalten bool IS durch Verwendung reinterpret_cast auf Zeiger:

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

Da dieser Code jedoch ohnehin zu undefiniertem Verhalten führt, können wir dieses potenzielle Problem bei der Konformen von C ++ - Code sicher ignorieren.


1 Zugegeben, dies ist eine ziemlich große Einschränkung, wie Angewes Kommentar zeigt:

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

Der Grund ist, dass b & 2 führt eine ganzzahlige Promotion durch, so dass der Ausdruck dann gleichwertig ist static_cast<int>(b) & 2, was in ... endet 0, was dann wieder in a konvertiert wird bool. Es ist also wahr, dass die Existenz eines operator &&= würde die Art der Art verbessern.

Andere Tipps

&& und & unterschiedliche Semantik haben: && bewertet den zweiten Operanden nicht, wenn der erste Operand ist false. dh so etwas wie

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

ist sicher, aber

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

ist nicht, obwohl beide Operanden vom Typ sind bool.

Das gleiche gilt für &= und |=:

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

wird sich anders verhalten als:

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

Kurze Antwort

Alle Betreiber +=, -=, *=, /=, &=, |=... sind arithmetisch und liefern die gleiche Erwartung:

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

Operatoren jedoch &&= und ||= wäre logisch, und diese Operatoren könnten fehleranfällig sein, weil viele Entwickler erwarten würden foo() immer einberufen werden 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
  • Müssen wir wirklich C/C ++ noch komplexer machen, um eine Abkürzung zu erhalten? x = x && foo()?

  • Wollen wir wirklich mehr die kryptische Aussage verschleiern? x = x && foo()?
    Oder wollen wir sinnvollen Code wie schreiben wie if (x) x = foo();?


Lange Antwort

Beispiel für &&=

Wenn &&= Der Bediener war verfügbar, dann dieser Code:

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

ist äquivalent zu:

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

Dieser erste Code ist fehleranfällig Weil viele Entwickler denken würden f2() wird immer genannt, was auch immer die f1() Rückgabewert. Es ist wie beim Schreiben bool ok = f1() && f2(); wo f2() wird nur dann aufgerufen, wenn f1() kehrt zurück true.

  • Wenn der Entwickler tatsächlich will f2() Nur aufgerufen zu werden, wenn f1() kehrt zurück true, Daher ist der zweite Code oben weniger fehleranfällig.
  • Sonst (der Entwickler will f2() immer genannt werden), &= ist ausreichend:

Beispiel für &=

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

Darüber hinaus ist es für Compiler einfacher, diesen oben genannten Code zu optimieren als der unter einem:

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

Vergleichen && und &

Wir fragen uns vielleicht, ob die Betreiber && und & Geben Sie das gleiche Ergebnis an, wenn Sie angewendet werden bool Werte?

Überprüfen Sie den folgenden C ++ - Code:

#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);
}

Ausgabe:

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

Fazit

Deswegen JAWOHL Wir können ersetzen && durch & zum bool Werte ;-)
Also besser benutzen &= Anstatt von &&=.
Wir können berücksichtigen &&= als nutzlos für Boolesche.

Gleiches für ||=

Operator |= ist auch weniger fehleranfällig als ||=

Wenn ein Entwickler will f2() nur dann aufgerufen werden, wenn f1() kehrt zurück false, Anstatt von:

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

Ich rate die folgende verständlichere Alternative:

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)

oder wenn Sie es vorziehen Alles in einer Zeile Stil:

// 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();
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top