如果将 &&=
和 ||=
用作 bool foo = foo && bar
和 bool foo = foo || bar
的语法糖,会不会发生"非常糟糕的事情"?
true
或false
。因此,使用&=
和|=
操作符相对安全(尽管我不太喜欢这种表示方法)。虽然它们执行的是位运算而不是逻辑运算(因此它们不会短路),但是只要两个操作数都是bool
类型,这些位运算将遵循明确定义的映射,与逻辑运算等效。1
与其他人所说的相反,在C++中,bool
绝不能有不同于true
或false
的值,如2
。当将该值赋给bool
时,它将按照标准被转换为true
。bool
类型包含无效值的方法是在指针上使用reinterpret_cast
操作符。int i = 2;
bool b = *reinterpret_cast<bool*>(&i);
b |= true; // MAY yield 3 (but doesn’t on my PC!)
但由于这段代码本身存在未定义行为,因此在符合C++标准的代码中可以安全地忽略这个潜在问题。
1诚然,正如Angew的评论所示,这是一个相当大的警告:
bool b = true;
b &= 2; // yields `false`.
b & 2
会进行整数提升,使得表达式等价于static_cast<int>(b) & 2
,这将导致结果为0
,然后再转换回bool
类型。因此,存在一个operator &&=
将会提高类型安全性。||
和 &&
会进行短路运算,也就是说,如果第一个操作数为 true
(&&
的情况下则为 false
),那么第二个操作数将不再被执行。而 |
、&
、|=
和 &=
则会始终对两个操作数进行求值。 - Nikibool
的左操作数来说,使用&=
运算符是不安全的,因为右操作数可能是除了bool
以外的其他类型(例如返回非零值表示真的islower
或另一个C标准库函数)。如果我们有假设性的&&=
运算符,它可能会强制将右操作数转换为bool
,而&=
则不会这样做。换句话说,bool b = true; b &= 2;
的结果是b == false
。 - Angew is no longer proud of SO&&
和&
具有不同的语义:&&
如果第一个操作数为false
,则不会计算第二个操作数。 比如:
flag = (ptr != NULL) && (ptr->member > 3);
是安全的,但是
flag = (ptr != NULL) & (ptr->member > 3);
尽管两个操作数都是bool
类型,但is not
运算符并不适用。
&=
和|=
同样如此:
flag = CheckFileExists();
flag = flag && CheckFileReadable();
flag = flag && CheckFileContents();
会表现出不同的行为:
flag = CheckFileExists();
flag &= CheckFileReadable();
flag &= CheckFileContents();
所有运算符+=
、-=
、*=
、/=
、&=
、|=
等都是算术运算符并提供相同的期望:
x &= foo() // We expect foo() be called whatever the value of x
然而,运算符&&=
和||=
是逻辑上的,这些运算符可能会出现错误,因为许多开发人员会期望x &&= foo()
中始终调用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
我们真的需要让 C/C++ 变得更加复杂,以便获取 x = x && foo()
的快捷方式吗?
我们真的想要更加混淆晦涩难懂的语句 x = x && foo()
吗?
或者我们想要编写有意义的代码,例如 if (x) x = foo();
吗?
&&=
的例子如果 &&=
运算符可用,那么这段代码:
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
等价于:
bool ok = true;
if (ok) ok = f1();
if (ok) ok = f2(); //f2() is called only when f1() returns true
这段代码存在错误风险,因为许多开发人员会认为f2()
总是被调用,而不管f1()
返回什么值,它就像写了bool ok = f1() && f2();
一样,在f1()
返回true
时才会调用f2()
。
f1()
返回true
时才调用f2()
,那么上面的第二个代码就更少出错。f2()
),&=
就足够了:&=
的示例bool ok = true;
ok &= f1();
ok &= f2(); //f2() always called whatever the f1() returned value
此外,编译器更容易优化上述代码而不是下面的代码:
bool ok = true;
if (!f1()) ok = false;
if (!f2()) ok = false; //f2() always called
&&
和 &
我们可能会想知道在应用于 bool
值时,运算符 &&
和 &
是否会得到相同的结果?
让我们使用以下 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);
}
输出:
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
======================
因此,是的,我们可以用 &
替换 &&
来处理 bool
值;-)
所以最好使用 &=
而不是 &&=
。
对于布尔值来说,&&=
可以被认为是无用的。
||=
同理操作符
|=
也比||=
更不容易出错。
如果开发人员只希望在 f1()
返回 false
时才调用 f2()
,而不是使用以下语法:
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 ...
我建议以下更易理解的替代方案:
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)
或者如果您喜欢一行显示的风格:
// 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();
success = success && DoImportantStuff()
。 - Niklas Rif(success) success = DoImportantStuff()
。如果允许语句 success &&= DoImportantStuff()
,许多开发人员会认为无论 success
的值如何,DoImportantStuff()
总是会被调用。希望这回答了您的疑问...我也改善了许多我的回答部分。请告诉我现在我的回答是否更容易理解?祝好,再见 ;-) - oHosuccess &&= DoImportantStuff()
,很多开发者会认为无论 success
是什么值,DoImportantStuff()
都会被调用。但是,如果他们记得 if 语句的逻辑,对于 &&=
应该没有问题。 - pilkchf1()
总是在 ok &&= f(1)
中被执行,而不认为它总是在 ok = ok && f(1)
中被执行。我认为这两种情况同样可能发生。 - einpoklumv1 += e2
是变量 v1 和表达式 e2 的语法糖等效于 v1 = v1 + e1
。只是一种简写符号,仅此而已。 - einpoklum
x ||= y
不是对于任何类型都等价于C++的x = x ? x : y;
吗?换句话说,“如果尚未设置,则设置为y”。这比C或C++的x ||= y
要有用得多,后者(除非进行运算符重载)将执行“将x设置为(bool)y
,除非已经设置”。我不急于添加另一个运算符,这似乎有点无力。只需编写if (!x) x = (bool)y
即可。但是,我并没有真正使用足够的bool
变量来希望具有仅与该一种类型真正有用的额外运算符。 - Steve Jessop&&=
或||=
的主要原因只是因为C语言没有这些运算符。我相当确定C语言没有这些运算符的原因是因为这种功能被认为不够有益。 - Jonathan Lefflerbool foo = foo || bar;
会引发未定义行为,因为在评估foo || bar
之前没有初始化foo
。当然,这是想要表达的意思类似于bool foo = …initialization…; …; foo = foo || bar;
,那么问题就是合法的。 - Jonathan Leffler