¿Por qué hay una advertencia de rendimiento en el puntero de conversión a bool?

7 minutos de lectura

avatar de usuario de bobobobo
bobobobo

Esta pregunta se extiende ¿Por qué usar !! al convertir int a bool?.

Pensé que estaba siendo genial cuando hice algo como:

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

Dónde this->parentNode es NULL cuando no hay un nodo principal.

Pero estoy recibiendo:

advertencia C4800: ‘Nodo *’: valor forzado a bool ‘verdadero’ o ‘falso’ (advertencia de rendimiento)

Incluso con un lanzamiento (bool), la advertencia aún no desaparece.

¿Cuál es el trato, yo? ¿Por qué es una advertencia de rendimiento? Pensé que sería menos eficiente escribir algo como:

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

Pero la segunda versión no genera advertencias y el compilador parece mucho más feliz. Sin embargo, ¿cuál es más rápido?

  • Solución alternativa: Cambiar (expr) a !!(expr)

    usuario2176127

    07/12/2013 a las 16:40

  • Eso parece demasiado emocionante.

    – bobobobo

    7 dic 2013 a las 16:59

Avatar de usuario de Michael Burr
miguel rebabas

Hay una discusión en Microsoft Connect sobre esto (¿Cuál es la implicación de rendimiento de convertir a bool en C++?). El ejemplo dado a Microsoft es:

$ 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)

Y la respuesta de Microsoft (del desarrollador responsable de la advertencia) es:

Esta advertencia es sorprendentemente útil y ayer encontré un error en mi código. Creo que Martin está sacando de contexto la “advertencia de desempeño”.

No se trata del código generado, se trata de si el programador ha señalado o no la intención de cambiar un valor de int a bool. Hay una penalización por eso, y el usuario tiene la opción de usar “int” en lugar de “bool” de manera consistente (o más probablemente viceversa) para evitar la generación de código “boolificante”. La advertencia se suprime en el tercer caso a continuación porque indica claramente su intención de aceptar la transición int->bool.

Es una advertencia antigua y puede haber sobrevivido a su propósito, pero se está comportando como se diseñó aquí.

Así que, básicamente, el desarrollador de MS parece estar diciendo que si desea “lanzar” un int a bool deberías hacerlo más correctamente usando “return this->parentNode != 0” en lugar de un molde implícito o explícito.

Personalmente, me interesaría saber más sobre qué tipo de errores descubre la advertencia. Creo que esta advertencia no tendría mucho valor.

  • Yo también creo que esta advertencia es inútil, pero nuevamente estoy sesgado contra MS VC 😉

    -Gunther Piez

    4 de diciembre de 2009 a las 16:24

  • Creo que debería haber un indicador del compilador para habilitar esas advertencias inútiles. Esta y las advertencias “la mayor parte de C y parte de la biblioteca estándar de C ++ están en desuso” siempre han creado una necesidad en mí simplemente de deshabilitar las advertencias cuando uso VC.

    – tío Bens

    4 de diciembre de 2009 a las 17:40

  • También return this->parentNode != 0 es más propenso a errores debido a un posible error tipográfico return this->parentNode = 0.

    – bobobobo

    6 de marzo de 2010 a las 17:00

  • bobobobo: Cualquier compilador cuerdo (al menos gcc) advertirá sobre eso. Y si usa “const” correctamente, hasParent() será una función const, por lo que sería un error de compilación.

    – usuario9876

    20 de octubre de 2010 a las 13:04

  • existe para pasas histéricas. Algunos compiladores antiguos no conformes (probablemente VStudio v. != 0 comparación, que es un OPCODE más lento que el cast que había antes en el generador de código. Entonces, el tipo que hizo eso, también emitió una advertencia … para advertir a los clientes de mantenimiento de bases de código antiguas que algo cambió a más lento con el nuevo compilador.

    – v.oddou

    10 de diciembre de 2013 a las 5:27

El hecho de que lanzar a bool no hace que la advertencia desaparezca es por diseño:

Convertir la expresión al tipo bool no deshabilitará la advertencia, que es por diseño.

Recomendaría el enfoque que recomienda la descripción de MSDN de la advertencia C4800:

return this->parentNode != NULL;

esto deja claro que vas a volver true si parentNode no es un puntero nulo y false si parentNode es un puntero nulo.

  • ¡Buena respuesta! Desde el punto de vista de la EM. Me gustaría expresar que no estoy de acuerdo … en mis declaraciones if, etc., nunca verifico if( object == NULL ) por la posibilidad de teclear if( object = NULL ) y creando un error de esta manera. compruebo if( object ) y if( !object ) precisamente por eso. #pragma warning (disable:4800)ahora escribo.

    – bobobobo

    6 de marzo de 2010 a las 17:02


  • prefiero emitir por !!value. Es más corto y más genérico.

    – Yakov Galka

    25 de noviembre de 2010 a las 9:20

  • +1 Hacer que la conversión sea explícita hace que su intención sea obvia para el próximo programador que lea el código y reconozca el costo de rendimiento de la conversión implícita.

    – Adrián McCarthy

    16 mayo 2012 a las 22:19

  • No responde a la pregunta: “¿Por qué hay una advertencia de rendimiento…”?

    – Jon

    23 de junio de 2014 a las 5:27

  • Algunos estándares de codificación sugieren cambiar los parámetros del operador alrededor del objeto NULL == para que el objeto NULL = tipográfico cause un error de compilación.

    –Denise Skidmore

    21 de abril de 2016 a las 20:08

Avatar de usuario de Gunther Piez
Gunther piez

El compilador necesita generar código adicional para convertir un puntero a bool. Básicamente es una comparación contra cero y establecer el resultado en uno, si no cero.

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

Esto no es directamente visible desde la fuente, por lo que el compilador cree que esto es algo sobre lo que se debe advertir al usuario.

  • No es porque esté convirtiendo un puntero en un bool, sino porque está devolviendo un bool. Este mismo código se genera si está comparando dos bools, pero usa diferentes registros según la configuración de optimización.

    – Michael J. Gray

    13/01/2017 a las 23:40

¿Por qué es una advertencia de rendimiento?

El compilador está convirtiendo esto:

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

dentro:

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

Esto toma alrededor un ciclo de reloj más de lo que cabría esperar al mirar el código. Es una diferencia de rendimiento insignificante.

Creo que es mejor escribir el != 0 explícitamente de todos modos, ya que hace que el código sea más claro y silencia la advertencia.

Avatar de usuario de Martin York
martín york

Sería más eficiente escribir:

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

  • Incorrecto, el compilador generará el mismo código que el original.

    – usuario9876

    4 de diciembre de 2009 a las 16:02

  • user9876, ¿quién dijo que generaría un código más eficiente? Se ahorra teclear.

    -Georg Fritzsche

    4 de diciembre de 2009 a las 16:05

  • La parte de escritura es épsilon más eficiente. La parte ejecutora es épsilon al cuadrado más eficiente. Llamar a esto una advertencia de rendimiento es solo parte de la idiotez general sobre el rendimiento.

    –Mike Dunlavey

    4 de diciembre de 2009 a las 16:15

  • Quise decir en comparación con el bloque if {} else {}. Esto también elimina la advertencia.

    – Martín York

    4 de diciembre de 2009 a las 17:20

  • @Martin: Sé que lo hiciste. Estaba en llamas por la advertencia del compilador original. Lo siento.

    –Mike Dunlavey

    5 de diciembre de 2009 a las 0:50

Avatar de usuario de UberJumper
UberJumper

Siendo realistas, creo que se optimizarían de la misma manera, también puedes intentar hacer esto:

return this->parentNode != 0;

  • Incorrecto, el compilador generará el mismo código que el original.

    – usuario9876

    4 de diciembre de 2009 a las 16:02

  • user9876, ¿quién dijo que generaría un código más eficiente? Se ahorra teclear.

    -Georg Fritzsche

    4 de diciembre de 2009 a las 16:05

  • La parte de escritura es épsilon más eficiente. La parte ejecutora es épsilon al cuadrado más eficiente. Llamar a esto una advertencia de rendimiento es solo parte de la idiotez general sobre el rendimiento.

    –Mike Dunlavey

    4 de diciembre de 2009 a las 16:15

  • Quise decir en comparación con el bloque if {} else {}. Esto también elimina la advertencia.

    – Martín York

    4 de diciembre de 2009 a las 17:20

  • @Martin: Sé que lo hiciste. Estaba en llamas por la advertencia del compilador original. Lo siento.

    –Mike Dunlavey

    5 de diciembre de 2009 a las 0:50

¿Ha sido útil esta solución?