140

是否有可能发生并被用作 and 的语法糖的“非常糟糕的事情”&&=||=bool foo = foo && barbool foo = foo || bar

4

3 回答 3

88

Abool只能是truefalse在 C++ 中。因此,使用&=and|=是相对安全的(尽管我不是特别喜欢这个符号)。确实,它们将执行位操作而不是逻辑操作(因此它们不会短路),但是这些位操作遵循定义明确的映射,这实际上等效于逻辑操作,只要两个操作数都是类型bool. 1

与其他人在这里所说的相反,boolC++ 中的 a 绝不能具有不同的值,例如2. 将该值分配给 abool时,它将true按照标准转换为。

将无效值放入 a 的唯一方法bool是使用reinterpret_caston 指针:

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,然后将其转换回 a bool。所以确实存在 anoperator &&=会提高类型安全性。

于 2010-03-21T20:02:57.527 回答
48

&&并且&具有不同的语义:&&如果第一个操作数是 ,则不会计算第二个操作数false。即类似的东西

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

是安全的,但是

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

不是,尽管两个操作数都是bool.

&=和也是如此|=

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

行为将不同于:

flag = CheckFileExists();
flag &= CheckFileReadable();
flag &= CheckFileContents();
于 2010-03-21T20:13:40.567 回答
29

简短的回答

所有运算符+=, -=, *=, /=, &=, |=... 都是算术运算并提供相同的期望:

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

但是,运算符&&=||=将是合乎逻辑的,并且这些运算符可能容易出错,因为许多开发人员希望foo()始终调用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
  • 我们真的需要让 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();wheref2()只在f1()返回时调用true

  • 如果开发人员实际上只想在返回f2()时被调用,那么上面的第二个代码不太容易出错。f1()true
  • 否则(开发人员希望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
======================

结论

因此,的,我们可以用 for values 替换&&;-)&所以bool更好
地使用&=而不是&&=.
我们可以认为&&=对于布尔值是无用的。

相同的||=

运算符的出错率|=也低于||=

如果开发人员只想在返回f2()时被调用,而不是:f1()false

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();
于 2012-03-29T15:28:06.217 回答