¿Puedo usar if (puntero) en lugar de if (puntero! = NULL)?

171

¿Es seguro marcar un puntero para no estar NULLescribiendo simplemente if(pointer)o tengo que usarlo if(pointer != NULL)?

danijar
fuente
13
La verdad es que si va a utilizar una verificación explícita, es igual de efectivo, y a menudo preferido, para probar 0o nullptr. ( NULLEs un C'ism, y requiere que incluye un archivo de cabecera.)
Chao
55
@danijar Puede usar nullptr en C ++ moderno.
SurvivalMachine
9
@cHao ¿Dónde está el punto de "apuntar a la compatibilidad con C"?
qdii
55
@danijar: Sí, no deberías usar NULLen C ++ a partir de aquí porque NULLes una macro dependiente de la implementación que puede darte comportamientos ambiguos.
Alok Save
3
Si bien este no es el caso 'if', vea esta demostración en vivo de ideone de por qué debería evitar "NULL" y "0" para los punteros en C ++: ideone.com/tbvXNs
kfsone

Respuestas:

198

Usted puede; el puntero nulo se convierte implícitamente en falso booleano, mientras que los punteros no nulos se convierten en verdadero. Desde el estándar C ++ 11, sección sobre conversiones booleanas:

Un valor de aritmética, enumeración sin ámbito, puntero o puntero a tipo de miembro se puede convertir a un valor de tipo bool. Se convierte un valor cero, un valor de puntero nulo o un valor de puntero de miembro nulo false; cualquier otro valor se convierte a true . Un valor de tipo std::nullptr_t puede convertirse en un valor de tipo bool ; el valor resultante es false .

Joni
fuente
42

Si, podrías.

  • Un puntero nulo se convierte en falso implícitamente
  • un puntero no nulo se convierte en verdadero.

Esto es parte de la conversión estándar de C ++, que se incluye en la cláusula de conversión booleana :

§ 4.12 Conversiones booleanas

Un valor de aritmética, enumeración sin ámbito, puntero o puntero a tipo de miembro se puede convertir en un valor de tipo bool. Un valor cero, un valor de puntero nulo o un valor de puntero de miembro nulo se convierte en falso; cualquier otro valor se convierte en verdadero. Un valor prva de tipo std :: nullptr_t puede convertirse en un valor prva de tipo bool; El valor resultante es falso.

billz
fuente
29

Sí tu puedes. De hecho, prefiero usarlo if(pointer)porque es más fácil de leer y escribir una vez que te acostumbras.

También tenga en cuenta que C ++ 11 introdujo nullptrque se prefiere sobre NULL.

Yu Hao
fuente
10
Un puntero no es una expresión booleana. Se convierte implícitamente. Si es mejor leer cuando tienes que recordar esta conversión, entender es tu opinión. Es solo un tipo de estilo de codificación.
Harper
77
@harper Puedes decir que es un estilo de codificación. Pero puedes aplicar la misma lógica a if(som_integer)vs if(some_integer != 0)porque los enteros tampoco son booleanos, ¿verdad? Prefiero evitar 0o NULLen una declaración if.
Yu Hao
13
Estoy de acuerdo en que es simplemente una cuestión de estilo de codificación. He llegado a preferirme a if (pointer)mí mismo, pero me if (ptr != nullptr)parece perfectamente legítimo. Por otro lado, si veía a alguien en mi equipo que escribiera if (some_integer), les haría cambiarlo if (some_integer != 0). Sin embargo, no voy a fingir que no es una preferencia relativamente arbitraria de mi parte, simplemente prefiero no tratar los punteros y los enteros de la misma manera.
Joel
1
@YuHao Y como es estilo de código, no diría "es preferido" sino "prefiero".
Harper
55
@ franji1 Entonces, ¿qué tal if(isReady) if(filePtr) if(serviceNo)? Hacer nombres de variables incorrectos a propósito no significa mucho en este caso. De todos modos, ya entendí tu punto y lo entendí, pero puedo insistir en usar mi propio estilo de codificación, ¿de acuerdo?
Yu Hao
13

La pregunta está respondida, pero me gustaría agregar mis puntos.

Siempre preferiré en if(pointer)lugar de if(pointer != NULL)y en if(!pointer)lugar de if(pointer == NULL):

  • Es simple, pequeño
  • Menos posibilidades de escribir un código erróneo, supongo que si lo escribo mal operador de comprobación de igualdad ==con =
    if(pointer == NULL)pueden estar mal escritas if(pointer = NULL)Así que voy a evitarlo, lo mejor es simplemente if(pointer).
    (También sugerí alguna condición de Yoda en una respuesta , pero esa es una cuestión diferente)

  • Del mismo modo while (node != NULL && node->data == key), simplemente escribiré lo while (node && node->data == key)que es más obvio para mí (lo demuestra usando cortocircuito).

  • (puede ser una razón estúpida) Porque NULL es una macro, si se supone que alguien redefine por error con otro valor.
Grijesh Chauhan
fuente
66
Usar = en lugar de == casi siempre genera una advertencia de compilación, en los días en que no lo haría la gente usaría if (NULL == ptr)
Paul
@paulm que acabo de agregar este punto se llama condición Yoda, a algunas personas no les gusta porque es menos legible.
Grijesh Chauhan
2
(boolean expression)? true : falseEs completamente inútil. La expresión evalúa to trueto to false; lo que dices es "si es verdad, dame verdad, si es falso, dame falso". En resumen: es completamente equivalente a la expresión booleana misma. Tenga en cuenta que node == NULLes una expresión booleana. Por cierto, sus dos implementaciones devuelven exactamente lo opuesto entre sí. O quieres !=en el primero, o solo uno !en el segundo.
celtschk
Por cierto, una posible protección contra en =lugar de ==es hacer sus variables constsiempre que sea ​​posible. Por ejemplo, podría definir su función como isEmnpy(node* const head) { ... }, y luego el compilador se negaría a compilarla si escribió accidentalmente en node = NULLlugar de node == NULL. Por supuesto, eso solo funciona para variables que realmente no necesita cambiar.
celtschk
2
Porque las clases de puntero inteligente tienen en T* get() constlugar de operator T*() constevitar conversiones implícitas. Sin embargo, tienen un operator bool() const.
StellarVortex
13

La comprobación explícita de NULL podría proporcionar una pista al compilador sobre lo que está tratando de hacer, por lo que puede ser menos propenso a errores.

ingrese la descripción de la imagen aquí

Minqi Pan
fuente
8

Sí tu puedes. La capacidad de comparar valores con ceros implícitamente se ha heredado de C, y existe en todas las versiones de C ++. También puede usar if (!pointer)para verificar los punteros para NULL.

dasblinkenlight
fuente
2

Los casos de uso relevantes para punteros nulos son

  • Redirección a algo como un nodo de árbol más profundo, que puede no existir o no ha sido vinculado todavía. Eso es algo que siempre debes mantener encapsulado en una clase dedicada, por lo que la legibilidad o la concisión no son un gran problema aquí.
  • Moldes dinámicos. Lanzar un puntero de clase base a uno particular de clase derivada (algo que debería intentar evitar de nuevo, pero que a veces puede ser necesario) siempre tiene éxito, pero da como resultado un puntero nulo si la clase derivada no coincide. Una forma de verificar esto es

    Derived* derived_ptr = dynamic_cast<Derived*>(base_ptr);
    if(derived_ptr != nullptr) { ... }

    (o, preferiblemente auto derived_ptr = ...) Ahora, esto es malo, porque deja el puntero derivado (posiblemente inválido, es decir, nulo) fuera del ifalcance del bloque de protección de seguridad . Esto no es necesario, ya que C ++ le permite introducir variables booleanas convertibles dentro de una ifcondición :

    if(auto derived_ptr = dynamic_cast<Derived*>(base_ptr)) { ... }

    que no solo es más corto y seguro para el alcance, también es mucho más claro en su intención: cuando verifica nulo en una condición if separada, el lector se pregunta "ok, entonces derived_ptrno debe ser nulo aquí ... bueno, ¿por qué será nulo? Mientras que la versión de una sola línea dice muy claramente "si se puede transmitir de forma segura base_ptraDerived* , y luego usarlo para ...".

    Lo mismo funciona igual de bien para cualquier otra operación de posible falla que devuelva un puntero, aunque IMO generalmente debería evitar esto: es mejor usar algo boost::optionalcomo el "contenedor" para obtener resultados de posibles operaciones fallidas, en lugar de punteros.

Entonces, si el caso de uso principal para punteros nulos siempre se debe escribir en una variación del estilo implícito, diría que es bueno, por razones de coherencia, usar siempre este estilo, es decir, abogaría por if(ptr)más if(ptr!=nullptr).


Me temo que tengo que terminar con un anuncio: la if(auto bla = ...)sintaxis es en realidad una aproximación un poco engorrosa a la solución real a tales problemas: la coincidencia de patrones . ¿Por qué forzarías primero alguna acción (como lanzar un puntero) y luego considerarías que podría haber una falla ... Quiero decir, es ridículo, ¿no? Es como si tuvieras algo de comida y quieres hacer sopa. Se lo entrega a su asistente con la tarea de extraer el jugo, si resulta ser un vegetal blando. No lo miras primero. Cuando tienes una papa, todavía se la das a tu asistente, pero te la devuelven en la cara con una nota de falla. ¡Ah, programación imprescindible!

Mucho mejor: considere de inmediato todos los casos que pueda encontrar. Entonces actúa en consecuencia. Haskell

makeSoupOf :: Foodstuff -> Liquid
makeSoupOf p@(Potato{..}) = mash (boil p) <> water
makeSoupOf vegetable
 | isSoft vegetable  = squeeze vegetable <> salt
makeSoupOf stuff  = boil (throwIn (water<>salt) stuff)

Haskell también tiene herramientas especiales para cuando realmente existe una posibilidad seria de falla (así como para un montón de otras cosas): mónadas. Pero este no es el lugar para explicarlos.

⟨/Propaganda⟩

a la izquierda
fuente
1
Solo puedo ver una oración en esta regla interminable que realmente responde a la pregunta.
Marqués de Lorne
@EJP: si tomas la pregunta literalmente (" puedo usarla"), entonces no se responde de manera explícita (la respuesta es simplemente "sí"). Traté de dar las razones adecuadas de por qué el OP debería de hecho usar en if(ptr)lugar de hacerlo if(ptr != nullptr), para lo cual hay mucho más que decir.
Leftaroundabout
1

¡sí, por supuesto! de hecho, escribir if (puntero) es una forma más conveniente de escribir que if (puntero! = NULL) porque: 1. es fácil de depurar 2. fácil de entender 3. si accidentalmente, se define el valor de NULL, entonces también el código no se bloqueará

Palak Jain
fuente
0

Si. De hecho deberías. Si se pregunta si crea una falla de segmentación , no lo hace.

darshandzend
fuente
29
¿Por qué deberías?
qdii
0

Como otros ya respondieron bien, ambos son intercambiables.

Sin embargo, vale la pena mencionar que podría haber un caso en el que desee utilizar la declaración explícita, es decir pointer != NULL.

Ver también https://stackoverflow.com/a/60891279/2463963

z3moon
fuente
-1

Sí, siempre puede hacer esto ya que la condición 'SI' se evalúa solo cuando la condición dentro de ella se cumple. C no tiene un tipo de retorno booleano y, por lo tanto, devuelve un valor distinto de cero cuando la condición es verdadera, mientras que devuelve 0 siempre que la condición en 'IF' sea falsa. El valor distinto de cero devuelto por defecto es 1. Por lo tanto, ambas formas de escribir el código son correctas, mientras que siempre preferiré el segundo.

usuario2280507
fuente
1
El valor distinto de cero por defecto es indefinido si no recuerdo mal.
Marqués de Lorne
-1

Creo que, como regla general, si su expresión if puede reescribirse como

const bool local_predicate = *if-expression*;
if (local_predicate) ...

de modo que NO provoque ADVERTENCIAS, entonces ESE debería ser el estilo preferido para la expresión if . (Sé que recibo advertencias cuando asigno un C BOOL( #define BOOL int) antiguo a un C ++ bool, por no hablar de punteros).

franji1
fuente
-1

"Es seguro..?" es una pregunta sobre el estándar de idioma y el código generado.

"¿Es una buena práctica?" es una pregunta sobre qué tan bien la declaración es entendida por cualquier lector humano arbitrario de la declaración. Si hace esta pregunta, sugiere que la versión "segura" es menos clara para futuros lectores y escritores.

Fred Mitchell
fuente
Mi intención era preguntar si es seguro. Por eso usé esa redacción. Sin embargo, lo que escribió aquí no es una respuesta a la pregunta. En cambio, debería ser un comentario debajo de la pregunta. Puede eliminar la respuesta y agregar un comentario debajo de la pregunta.
danijar
@danijar ¿No recuerda cuándo era nuevo en StackOverflow y buscó la sección 'Comentario' sin éxito? Alguien con 7 reputación no puede hacer eso.
Broxzier
@JimBalter Lo cual es muy confuso, ya que puedes ver que otros lo hacen. Cuando era nuevo en SO alguien me culpó por hacer eso.
Broxzier
@ JimBalter No estoy asesinando ni robando. Le estaba diciendo a Danijar que Fred Mitchell era un nuevo usuario y no podía publicar comentarios.
Broxzier
@JimBalter Que empezaste hoy. También eres el que no entiende en su lugar. Ese comentario solo respalda la confusión de esto.
Broxzier