Вопрос

Есть ли "Очень плохо" это может произойти && = и || = использовалось в качестве синтаксического сахара для bool foo = foo && bar а также bool foo = foo || bar?

Это было полезно?

Решение

А 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 По общему признанию, это довольно большое предостережение, как иллюстрирует комментарий Ангеу:

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

Причина в том, что b & 2 выполняет целочисленное продвижение, так что выражение затем эквивалентно static_cast<int>(b) & 2, что приводит к 0, который затем превращается обратно в bool. Анкет Так что это правда, что существование operator &&= улучшит безопасность типа.

Другие советы

&& а также & иметь разные семантики: && не оценит второй операнд, если первый операнд 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();

Короткий ответ

Все операторы +=, -=, *=, /=, &=, |=... арифметики и обеспечивают одинаковое ожидание:

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