代码之家  ›  专栏  ›  技术社区  ›  Kache

为什么C++不具有布尔代数的& & =或ω=?

  •  99
  • Kache  · 技术社区  · 14 年前

    有没有 "very bad thing" 可能发生的情况&=和用作 bool foo = foo && bar bool foo = foo || bar ?

    3 回复  |  直到 5 年前
        1
  •  63
  •   Konrad Rudolph    5 年前

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

    与其他人所说的相反, 布尔 在C++中绝对不能有不同的值,比如 2 . 当将该值赋给 布尔 ,将转换为 按标准执行。

    获取无效值的唯一方法 布尔 是通过使用 reinterpret_cast 指针:

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

    但是,由于这个代码导致了未定义的行为,我们可以在忽略C++代码时安全地忽略这个潜在的问题。


    诚然,这是一个相当大的警告,正如Angew_

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

    原因是 b & 2 执行整数提升,这样表达式就等于 static_cast<int>(b) & 2 从而导致 0 ,然后转换回 布尔 . 因此,确实存在 operator &&= 会提高类型安全性。

        2
  •  42
  •   Niki    14 年前

    && & 有不同的语义: && 如果第一个操作数是 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();
    
        3
  •  20
  •   oHo Denis Tulskiy    7 年前

    简短回答

    所有操作员 += , -= , *= ,请 /= ,请 &= , |= …是算术的,并且提供相同的期望:

    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 .

    • 如果开发者真的想要 第2页) 只有在 F1() 收益率 因此,上面的第二个代码不太容易出错。
    • 其他(开发商希望 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
    ======================
    

    结论

    因此 我们可以替换 && 通过 & 对于 布尔 值;-)
    所以更好地使用 &= 而不是 &&= .
    我们可以考虑 &&= 对布尔人没用。

    同样 =

    操作人员 = 也少 易出错的 =

    如果开发者想要 第2页) 只有在 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();