c++ - que - ¿Es nullptr falso?
nullptr vs null (3)
Cuando se usa como una expresión booleana o se transforma en booleana, ya sea explícita o implícitamente, ¿es
nullptr
constantemente falso?
¿Esta implementación está definida o especificada en el estándar?
Escribí un código para probar, pero no estoy seguro de si prueba esta propiedad completamente. No pude encontrar una respuesta SO existente que hablara específicamente sobre esto. cppreference no menciona esto por lo que veo.
if (nullptr) {
;
} else {
std::cout << "Evaluates to false implicitly/n";
}
if (!nullptr) {
std::cout << "Evaluates to false if operated on/n";
}
if (!(bool)(nullptr)) {
std::cout << "Evaluates to false if explicitly cast to bool/n";
}
Esperado y actual:
Evaluates to false implicitly
Evaluates to false if operated on
Evaluates to false if explicitly cast to bool
Sí, pero debes evitar usar este hecho.
Comparar punteros con
false
, o con
0
, es un tropo común en la codificación C / C ++.
Le sugiero que
evite usarlo
.
Si desea verificar la nulidad, use:
if (x == nullptr) { /* ... */}
más bien que
if (!x) { /* ... */}
o
if (not x) { /* ... */}
La segunda variante agrega otro poco de confusión para el lector: ¿Qué es
x
?
¿Es un booleano?
¿Un valor simple (por ejemplo, un entero)?
Un puntero?
Un opcional?
Incluso si
x
tiene un nombre significativo, no lo ayudará mucho:
if (!network_connection)
... aún podría ser una estructura compleja convertible en un entero o un booleano, podría ser un indicador booleano de si hay una conexión , podría ser un puntero, un valor o un opcional.
O algo mas.
Además, recordar que
nullptr
evalúa como falso es otra información que necesita almacenar en la parte posterior de su cerebro para decodificar correctamente el código que está leyendo.
Podemos estar acostumbrados desde los viejos tiempos o desde la lectura del código de otras personas, pero si no lo estuviéramos, no habría sido obvio que
nullptr
comporta así.
En cierto sentido, no es diferente para otras garantías oscuras, como cómo se garantiza que
el valor en el índice 0 de un
std::string
vacío sea
/0
.
Simplemente no hagas que tu código confíe en estas cosas a menos que sea absolutamente necesario.
PD: actualmente hay mucho menos uso para los punteros nulos en estos días.
Puede
forzar el puntero para que nunca sea nulo
si no es necesario;
puede usar referencias en lugar de punteros;
y puede usar
std::optional<T>
para devolver una
T
o "no T".
Tal vez podría evitar mencionar
nullptr
completo.
De acuerdo con el estándar C ++ 17 (5.13.7 literales de puntero)
1 El puntero literal es la palabra clave nullptr. Es un valor de tipo std :: nullptr_t. [Nota: std :: nullptr_t es un tipo distinto que no es un tipo de puntero ni un tipo de puntero a miembro; más bien, un valor de este tipo es una constante de puntero nulo y puede convertirse en un valor de puntero nulo o un valor de puntero de miembro nulo. Ver 7.11 y 7.12. - nota final]
Y (7 conversiones estándar)
4 Ciertas construcciones de lenguaje requieren que una expresión se convierta en un valor booleano. Se dice que una expresión e que aparece en dicho contexto se convierte contextualmente en bool y está bien formada si y solo si la declaración bool t (e); está bien formado , para algunas variables temporales inventadas t (11.6).
Y por fin (7.14 conversiones booleanas)
1 Un valor de aritmética, enumeración sin ámbito, puntero o tipo de puntero a 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. Para la inicialización directa (11.6), un valor prva de tipo std :: nullptr_t puede convertirse en un valor prva de tipo bool; El valor resultante es falso.
Es decir, puedes escribir por ejemplo
bool b( nullptr );
pero no puede escribir (aunque algunos compiladores tienen un error relacionado con esto)
bool b = nullptr;
Por lo tanto,
nullptr
puede convertirse contextualmente en un objeto del tipo bool, por ejemplo, en sentencias de selección como la sentencia if.
¡Consideremos, por ejemplo, el operador unario
!
como en una declaración if
if ( !nullptr ) { /*...*/ }
Según la descripción del operador (8.5.2.1 Operadores unarios)
9 ¡ El operando del operador de negación lógica! se convierte contextualmente a bool (Cláusula 7); su valor es verdadero si el operando convertido es falso y falso de lo contrario. El tipo de resultado es bool
Entonces
nullptr
en esta expresión no se convierte en un puntero.
Se convierte directamente contextualmente a bool.
El resultado de su código está garantizado, [dcl.init]/17.8
De lo contrario, si la inicialización es de inicialización directa, el tipo de origen es
std::nullptr_t
y el tipo de destino esbool
, el valor inicial del objeto que se inicializa esfalse
.
Eso significa que, para la inicialización directa, un objeto
bool
puede inicializarse desde
nullptr
, con el valor del resultado
false
.
Luego, para
(bool)(nullptr)
,
nullptr
se convierte en
bool
con el valor
false
.
¡Cuando se usa
nullptr
como condición de
if
o el operando del
operator!
, se considera como
conversiones contextuales
,
la conversión implícita se realiza si la declaración
bool t(e);
está bien formado
Eso significa que tanto
if (nullptr)
como
!nullptr
,
nullptr
se convertirán en
bool
con valor
false
.