Почему существует предупреждение о производительности при приведении указателя на bool?


выходит.

Я думал, что я был крут, когда я сделал что-то вроде:

bool hasParent()
{
  return this->parentNode ;
}

даже с A (bool) cast, предупреждение все еще не уходит.

где это - > parentNode имеет значение NULL, когда нет родительского узла.

но я получаю:

warning C4800: 'Node *' : forcing value to bool 'true' or 'false' (performance warning)

в чем дело, йо? Почему это предупреждение о производительности? Я думал, что было бы более эффективно не писать что-то вроде:


bool hasParent()
{
  if( this->parentNode )
    return true ;
  else
    return false ;
}

но второй версия генерирует никаких предупреждений и компилятор, кажется, намного счастливее. Что быстрее, хотя?

7 53

7 ответов:

есть обсуждение на Microsoft Connect об этом (какова производительность преобразования в bool в C++?). Пример, приведенный в Microsoft:

$ cat -n t.cpp && cl -c -W3 -O2 -nologo -Fa t.cpp
1 bool f1 (int i)
2 {
3 return i & 2;
4 }
5
6 bool f2 (int i)
7 {
8 const bool b = i & 2;
9 return b;
10 }
11
12 bool f3 (int i)
13 {
14 const bool b = 0 != (i & 2);
15 return b;
16 }
t.cpp
t.cpp(3) : warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning)
t.cpp(8) : warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning)

и ответ Microsoft (от разработчика, ответственного за предупреждение):

это предупреждение удивительно полезно, и нашел ошибку в моем коде только вчера. Я думаю, что Мартин берет "предупреждение о производительности" из контекста.

дело не в этом сгенерированный код, это о том, сигнализировал ли программист о намерении изменить значение с int на bool. Существует штраф за это, и у пользователя есть выбор использовать "int" вместо "bool" последовательно (или, скорее всего, наоборот), чтобы избежать "логического" codegen. Предупреждение подавляется в третьем случае ниже, потому что он явно сигнализировал о своем намерении принять переход int->bool.

это старое предупреждение, и, возможно, изжило свою цель, но он ведет себя так, как задумано здесь

так что в основном разработчик MS, похоже, говорит, что если вы хотите "бросить"int to bool вы должны более правильно делать это с помощью "return this->parentNode != 0" вместо неявного или явного приведения.

лично мне было бы интересно узнать больше о том, какие ошибки предупреждение раскрывает. Я думаю, что это предупреждение не будет иметь большого значения.

дело в том, что кастинг на bool не делает предупреждение уйти по проекту:

приведение выражения к типу bool не отключит предупреждение, которое по дизайну.

Я бы рекомендовал подход, который рекомендует описание MSDN предупреждения C4800:

return this->parentNode != NULL;

это дает понять, что вы возвращаетесь true Если parentNode не является нулевым указателем и false если parentNode - нулевой указатель.

компилятор должен генерировать дополнительный код для конвертации указателя в bool. Это в основном сравнение с нулем и установка результата на один, если не ноль.

00000000004005e0 <_Z4testPv>:
bool test(void* adr) {
  4005e0:       48 85 ff                test   %rdi,%rdi
  4005e3:       0f 95 c0                setne  %al
    return adr;
}
  4005f8:       c3                      retq

это не видно непосредственно из источника, поэтому компилятор считает, что это то, о чем пользователь должен быть предупрежден.

Почему это предупреждение о производительности?

компилятор превращает этот:

bool hasParent()
{
  return this->parentNode;
}

в:

bool hasParent()
{
  return this->parentNode != 0;
}

это займет около часы больше, чем вы могли бы ожидать, глядя на код. Это незначительная разница в производительности.

Я думаю, что лучше написать != 0 явно в любом случае, так как это делает код более ясным, а также глушит предупреждение.

было бы эффективнее написать:

bool hasParent()
{
    return  this->parentNode != NULL;
}

Я уверен, что это зависит от компилятора

реально, я думаю, что они будут оптимизировать, к тому же, вы можете также попробовать сделать это:

return this->parentNode != 0;