c++ - resueltos - ¿Puedo usar if(puntero) en lugar de if(puntero!=NULL)?
punteros a cadenas (12)
¿Es seguro comprobar que un puntero no sea NULL
escribiendo simplemente if(pointer)
o tengo que usar if(pointer != NULL)
?
"Es seguro..?" es una pregunta sobre el estándar de lenguaje y el código generado.
"¿Es una buena práctica?" es una pregunta sobre qué tan bien entiende la declaración cualquier lector humano arbitrario de la declaración. Si hace esta pregunta, sugiere que la versión "segura" es menos clara para los futuros lectores y escritores.
¡sí, por supuesto! de hecho, escribir if (puntero) es una manera más conveniente de escribir en lugar de 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á
Creo que, como regla general, si su expresión if se puede volver a escribir como
const bool local_predicate = *if-expression*;
if (local_predicate) ...
de tal manera que NO HACE NINGUNA ADVERTENCIA, entonces ESO debería ser el estilo preferido para la expresión if . (Sé que recibo advertencias cuando asigno un antiguo C BOOL
( #define BOOL int
) a un C ++ bool
, y mucho menos punteros.)
La pregunta es respondida, pero me gustaría agregar mis puntos.
Siempre preferiré if(pointer)
lugar de if(pointer != NULL)
y if(!pointer)
lugar de if(pointer == NULL)
:
- Es simple, pequeño
Menos posibilidades de escribir un código con errores, supongamos que si escribo mal el operador de verificación de igualdad
==
con=
if(pointer == NULL)
puede estar mal escritoif(pointer = NULL)
Entonces lo evitaré, lo mejor es soloif(pointer)
.
(También sugerí alguna condición de Yoda en una respuesta , pero esa es una cuestión diferente)De manera similar para
while (node != NULL && node->data == key)
, simplemente escribiréwhile (node && node->data == key)
que es más obvio para mí (muestra que usando short-circuit).- (puede ser una razón estúpida) Debido a que NULL es una macro, supongamos que alguien redefina por error con otro valor.
Los casos de uso relevantes para punteros nulos son
- Redirección a algo así como un nodo de árbol más profundo, que puede no existir o no ha sido vinculado aún. Eso es algo que siempre debe mantenerse estrechamente encapsulado en una clase dedicada, por lo que la legibilidad o concisión no es un gran problema aquí.
Moldes dinámicos. Lanzar un puntero de clase base a una clase derivada particular (algo que debe intentar de nuevo evitar, pero 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 alcance del bloque de protección de seguridad. Esto no es necesario, ya que C ++ le permite introducir variables boolean-convertibles dentro de una condición-if
: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 se comprueba null en una condición if independiente, el lector se pregunta "está bien, así que
derived_ptr
no debe ser nula aquí ... bueno, ¿por qué? ¿Sería nulo? Mientras que la versión de una línea dice muy claramente "si puedes lanzarbase_ptr
aDerived*
, entoncesbase_ptr
para ...".Lo mismo funciona igual para cualquier otra operación de falla posible que devuelve un puntero, aunque generalmente debería evitar esto: es mejor usar algo como
boost::optional
como el "contenedor" para obtener resultados de operaciones que posiblemente fallen, en lugar de punteros.
Por lo tanto, si el caso de uso principal para punteros nulos debe escribirse siempre en una variación del estilo de reparto implícito, diría que es bueno por razones de coherencia usar siempre este estilo, es decir, defendería if(ptr)
sobre if(ptr!=nullptr)
.
Me temo que tengo que terminar con un anuncio: la sintaxis if(auto bla = ...)
es en realidad una aproximación algo engorrosa a la solución real a tales problemas: coincidencia de patrones . ¿Por qué primero deberías forzar alguna acción (como lanzar un puntero) y luego considerar que podría haber un error ... Es decir, es ridículo, ¿no? Es como, tienes algo de comida y quieres hacer sopa. Se lo entregas a tu asistente con la tarea de extraer el jugo, si resulta ser un vegetal blando. No lo mires primero. Cuando tienes una patata, todavía se la das a tu asistente pero la devuelven a la cara con una nota de falla. Ah, ¡programación imperativa!
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 hay una posibilidad seria de falla (así como para un montón de otras cosas): mónadas. Pero este no es el lugar para explicarlos.
& langle; / public & rangle;
Sí tu puedes. De hecho, prefiero usar 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 nullptr
que es preferible a NULL
.
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)
Pointer if (!pointer)
para marcar punteros para NULL.
Sí, siempre puedes hacer esto ya que la condición ''IF'' evalúa solo cuando la condición dentro de él 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 cuando la condición en ''SI'' resulta ser 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.
Sí. De hecho deberías. Si se está preguntando si crea un error de segmentación , no es así.
Si, podrías.
- Un puntero nulo se convierte a falso implícitamente
- un puntero no nulo se convierte en verdadero.
Esto es parte de la conversión estándar de C ++, que cae en la cláusula de conversión booleana :
§ 4.12 conversiones booleanas
Un prvalor de enumeración aritmética, sin cobertura, puntero o puntero a tipo de miembro se puede convertir a un prvalue 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 prvalue de tipo std :: nullptr_t se puede convertir a un prvalue de tipo bool; el valor resultante es falso.
Usted puede; el puntero nulo se convierte implícitamente en booleano falso mientras que los punteros no nulos se convierten en verdadero. Desde el estándar C ++ 11, sección sobre Conversiones Booleanas:
Un prvalor de enumeración aritmética, sin cobertura, puntero o puntero a tipo de miembro se puede convertir a un prvalue de tipo
bool
. Un valor cero, un valor de puntero nulo o un valor de puntero de miembro nulo se convierte enfalse
; cualquier otro valor se convierte entrue
. Un prvalue de tipostd::nullptr_t
se puede convertir a un prvalue de tipobool
; el valor resultante esfalse
.