Y a-t-il une "très mauvaise chose" qui peut se produire && = et || = ont été utilisés comme sucre syntaxique pour bool foo = foo && bar
et bool foo = foo || bar
?
Un bool
peut uniquement être true
ou false
en C++. En tant que tel, utiliser &=
Et |=
Est relativement sûr (même si je n'aime pas particulièrement la notation). Certes, ils effectueront des opérations binaires plutôt que des opérations logiques (et donc ils ne court-circuiteront pas), mais ces opérations binaires suivent un mappage bien défini, qui est effectivement équivalent aux opérations logiques, tant que les deux opérandes sont de type bool
.1
Contrairement à ce que d'autres personnes ont dit ici, un bool
en C++ ne doit jamais avoir une valeur différente telle que 2
. Lorsque vous affectez cette valeur à un bool
, elle sera convertie en true
selon la norme.
La seule façon d'obtenir une valeur non valide dans un bool
est d'utiliser reinterpret_cast
Sur les pointeurs:
int i = 2;
bool b = *reinterpret_cast<bool*>(&i);
b |= true; // MAY yield 3 (but doesn’t on my PC!)
Mais puisque ce code entraîne de toute façon un comportement indéfini, nous pouvons ignorer en toute sécurité ce problème potentiel dans la conformité du code C++.
1 Certes, il s'agit d'une mise en garde assez importante, comme l'illustre le commentaire d'Angew:
bool b = true;
b &= 2; // yields `false`.
La raison en est que b & 2
Effectue une promotion d'entier telle que l'expression est alors équivalente à static_cast<int>(b) & 2
, ce qui donne 0
, Qui est ensuite reconverti en bool
. Il est donc vrai que l'existence d'un operator &&=
Améliorerait la sécurité des types.
&&
et &
ont une sémantique différente: &&
n'évaluera pas le deuxième opérande si le premier opérande est false
. c'est-à-dire quelque chose comme
flag = (ptr != NULL) && (ptr->member > 3);
est sûr, mais
flag = (ptr != NULL) & (ptr->member > 3);
ne l'est pas, bien que les deux opérandes soient de type bool
.
Il en va de même pour &=
et |=
:
flag = CheckFileExists();
flag = flag && CheckFileReadable();
flag = flag && CheckFileContents();
se comportera différemment de:
flag = CheckFileExists();
flag &= CheckFileReadable();
flag &= CheckFileContents();
Tous les opérateurs +=
, -=
, *=
, /=
, &=
, |=
... sont arithmétiques et fournir la même attente:
x &= foo() // We expect foo() be called whatever the value of x
Cependant, les opérateurs &&=
Et ||=
Seraient logiques, et ces opérateurs pourraient être sujets à erreur car de nombreux développeurs s'attendraient à ce que foo()
soit toujours appelé dans 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
Avons-nous vraiment besoin de rendre le C/C++ encore plus complexe pour obtenir un raccourci pour x = x && foo()
?
Voulons-nous vraiment obscurcir davantage l'instruction cryptique x = x && foo()
?
Ou voulons-nous écrire du code significatif comme if (x) x = foo();
?
&&=
Si l'opérateur &&=
Était disponible, alors ce 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
est équivalent à:
bool ok = true;
if (ok) ok = f1();
if (ok) ok = f2(); //f2() is called only when f1() returns true
Ce premier code est sujet aux erreurs car de nombreux développeurs penseraient que f2()
est toujours appelée quelle que soit la valeur renvoyée par f1()
. C'est comme écrire bool ok = f1() && f2();
où f2()
est appelé uniquement lorsque f1()
renvoie true
.
f2()
soit appelé uniquement lorsque f1()
renvoie true
, le deuxième code ci-dessus est donc moins sujet aux erreurs.f2()
soit toujours appelée), &=
Est suffisant:&=
bool ok = true;
ok &= f1();
ok &= f2(); //f2() always called whatever the f1() returned value
De plus, il est plus facile pour le compilateur d'optimiser ce code ci-dessus que celui ci-dessous:
bool ok = true;
if (!f1()) ok = false;
if (!f2()) ok = false; //f2() always called
&&
Et &
On peut se demander si les opérateurs &&
Et &
Donnent le même résultat lorsqu'ils sont appliqués sur des valeurs bool
?
Vérifions à l'aide du code C++ suivant:
#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);
}
Sortie:
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
======================
Par conséquent OUI nous pouvons remplacer &&
Par &
Pour les valeurs de bool
;-)
Il vaut donc mieux utiliser &=
Au lieu de &&=
.
Nous pouvons considérer &&=
Comme inutile pour les booléens.
||=
l'opérateur
|=
est également moins sujet aux erreurs que||=
Si un développeur souhaite que f2()
soit appelé uniquement lorsque f1()
renvoie false
, au lieu 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 ...
Je conseille l'alternative la plus compréhensible suivante:
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)
ou si vous préférez tout en une ligne style:
// 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();