有没有 “非常糟糕的事情” 可能会发生 &&= 和 ||= 被用作语法糖 bool foo = foo && barbool foo = foo || bar?

有帮助吗?

解决方案

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

与其他人在这里所说的相反, bool 在 C++ 中决不能有不同的值,例如 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 &&= 会提高类型安全性。

其他提示

&&& 有不同的语义: && 如果第一个操作数是,则不会评估第二个操作数 false. 。IE。就像是

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();

简短回答

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

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(); 在哪里 f2() 仅当 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
======================

结论

所以 是的 我们可以替换 && 经过 & 为了 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();
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top