sirve que para not declared c++ c++11 implicit-conversion nullptr

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 es bool , el valor inicial del objeto que se inicializa es false .

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 .