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

Расширяет.

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

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

Даже при использовании (bool) предупреждение все равно не исчезает.

Если this- > parentNode равен NULL, если родительский node отсутствует.

Но я получаю:

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

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

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

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

Ответ 1

Здесь обсуждается Microsoft Connect об этом (Какова производительность преобразования в bool на С++?). Пример, предоставленный 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" последовательно (или, скорее, наоборот), чтобы избежать "boolifying" codegen. Предупреждение подавляется в третьем случае ниже, потому что он ясно сигнализировал о своем намерении принять переход int- > bool.

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

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

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

Ответ 2

Тот факт, что кастинг на bool не выводит предупреждение по дизайну:

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

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

return this->parentNode != NULL;

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

Ответ 3

Компилятор должен сгенерировать дополнительный код для преобразования указателя в 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

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

Ответ 4

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

Компилятор поворачивает это:

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

в

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

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

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

Ответ 5

Было бы более удобно писать:

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

Ответ 6

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

Ответ 7

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

return this->parentNode != 0;