Ahora tenemos C ++ 11 con muchas características nuevas. Una interesante y confusa (al menos para mí) es la nueva nullptr.
Bueno, ya no hay necesidad de la desagradable macro NULL.
int* x = nullptr;
myclass* obj = nullptr;
Aún así, no entiendo cómo nullptrfunciona. Por ejemplo, el artículo de Wikipedia dice:
C ++ 11 corrige esto mediante la introducción de una nueva palabra clave para servir como una constante de puntero nulo distinguido: nullptr. Es del tipo nullptr_t , que es implícitamente convertible y comparable a cualquier tipo de puntero o tipo de puntero a miembro. No es implícitamente convertible o comparable a los tipos integrales, excepto bool.
¿Cómo es una palabra clave y una instancia de un tipo?
Además, ¿tiene otro ejemplo (además del de Wikipedia) en el que nullptres superior a los buenos viejos 0?

nullptrtambién se utiliza para representar referencias nulas para identificadores administrados en C ++ / CLI.nullptr_tgarantiza tener un solo miembronullptr? Entonces, si se devuelve una funciónnullptr_t, entonces el compilador ya sabe qué valor se devolverá, independientemente del cuerpo de la función.std::nullptr_tse puede instanciar, pero todas las instancias serán idénticasnullptrporque el tipo se define comotypedef decltype(nullptr) nullptr_t. Creo que la razón principal por la que existe el tipo es para que las funciones se puedan sobrecargar específicamente para capturarnullptr, si es necesario. Ver aquí para un ejemplo.Respuestas:
Esto no es sorprendente. Ambos
trueyfalseson palabras clave y como literales tienen un tipo (bool).nullptres un puntero literal de tipostd::nullptr_t, y es un prvalue (no puede tomar la dirección usando&).4.10acerca de la conversión de puntero dice que un valor de tipostd::nullptr_tes una constante de puntero nulo, y que se puede convertir una constante de puntero nulo integralstd::nullptr_t. La dirección opuesta no está permitida. Esto permite sobrecargar una función tanto para punteros como enteros, y pasarnullptrpara seleccionar la versión del puntero. PasandoNULLo0seleccionaría confusamente laintversión.Un molde de
nullptr_tun tipo integral necesita unreinterpret_cast, y tiene la misma semántica que un molde de(void*)0un tipo integral (implementación de mapeo definida). Areinterpret_castno se puede convertirnullptr_ta ningún tipo de puntero. Confíe en la conversión implícita si es posible o usestatic_cast.El estándar requiere que
sizeof(nullptr_t)seasizeof(void*).fuente
cond ? nullptr : 0;. Eliminado de mi respuesta.NULLni siquiera se garantiza que sea0. Puede ser0L, en cuyo caso una llamada avoid f(int); void f(char *);será ambigua.nullptrsiempre favorecerá la versión de puntero, y nunca llamará a la versiónint. También tenga en cuenta quenullptres convertible abool(el borrador dice que en4.12).intversión. Perof(0L)es ambiguo, porquelong -> inttambiénlong -> void*es igualmente costoso. Entonces, si NULL está0Len su compilador, entonces una llamadaf(NULL)será ambigua dadas esas dos funciones. No es así, pornullptrsupuesto.(void*)0en C ++. Pero se puede definir como cualquier constante de puntero nulo arbitrario, que cualquier constante integral con valor 0 ynullptrcumplir. Por lo tanto, definitivamente no lo hará, pero puede . (Olvidó hacerme ping por cierto ...)De nullptr: un puntero nulo de tipo seguro y claro :
Otras referencias:
templatefuente
¿Por qué nullptr en C ++ 11? ¿Qué es? ¿Por qué NULL no es suficiente?
El experto en C ++ Alex Allain lo dice perfectamente aquí (mi énfasis se agrega en negrita):
Allain termina su artículo con:
(Mis palabras):
Por último, no olvides que
nullptres un objeto, una clase. Se puede usar en cualquier lugar dondeNULLse usaba antes, pero si necesita su tipo por alguna razón, su tipo se puede extraerdecltype(nullptr)o describir directamente comostd::nullptr_t, que es simplemente unatypedefdedecltype(nullptr).Referencias
fuente
Cuando tiene una función que puede recibir punteros a más de un tipo, llamarlo con
NULLes ambiguo. La forma en que esto se soluciona ahora es muy hacky al aceptar un int y asumir que esNULL.En
C++11sería capaz de sobrecargarse, pornullptr_tlo queptr<T> p(42);sería un error en tiempo de compilación en lugar de un tiempo de ejecuciónassert.fuente
NULLse define como0L?nullptrno se puede asignar a un tipo integral como, por ejemplo, uninttipo de puntero; ya sea un tipo de puntero incorporado comoint *ptro un puntero inteligente comostd::shared_ptr<T>Creo que esta es una distinción importante porque
NULLtodavía se puede asignar tanto a un tipo integral como a un puntero, ya queNULLes una macro expandida a la0que puede servir tanto como un valor inicial para unintpuntero como para un puntero.fuente
NULLno se garantiza que se expanda a0.Si. También es un ejemplo (simplificado) del mundo real que ocurrió en nuestro código de producción. Solo se destacó porque gcc pudo emitir una advertencia al realizar una compilación cruzada a una plataforma con un ancho de registro diferente (aún no está seguro exactamente por qué solo cuando se realiza una compilación cruzada de x86_64 a x86, advierte
warning: converting to non-pointer type 'int' from NULL):Considere este código (C ++ 03):
Produce esta salida:
fuente
Bueno, otros idiomas tienen palabras reservadas que son instancias de tipos. Python, por ejemplo:
Esta es en realidad una comparación bastante estrecha porque
Nonegeneralmente se usa para algo que no se ha inicializado, pero al mismo tiempo comparaciones comoNone == 0son falsas.Por otro lado, en C simple,
NULL == 0devolvería IIRC verdadero porqueNULLes solo una macro que devuelve 0, que siempre es una dirección no válida (AFAIK).fuente
NULLes una macro que se expande a cero, una conversión constante de cero a un puntero produce un puntero nulo. Un puntero nulo no tiene que ser cero (pero a menudo lo es), el cero no siempre es una dirección no válida, y una conversión de cero no constante a un puntero no tiene que ser nula, y un puntero nulo emitido a un entero no tiene que ser cero. Espero haberlo hecho bien sin olvidar nada. Una referencia: c-faq.com/null/null2.htmlEs una palabra clave porque el estándar la especificará como tal. ;-) Según el último borrador público (n2914)
Es útil porque no se convierte implícitamente en un valor integral.
fuente
Digamos que tiene una función (f) que está sobrecargada para tomar tanto int como char *. Antes de C ++ 11, si deseaba llamarlo con un puntero nulo y usaba NULL (es decir, el valor 0), llamaría al sobrecargado para int:
Esto probablemente no sea lo que querías. C ++ 11 resuelve esto con nullptr; Ahora puedes escribir lo siguiente:
fuente
Déjame primero darte una implementación de sofisticación
nullptr_tnullptres un ejemplo sutil de la expresión de resolución de tipo de retorno para deducir automáticamente un puntero nulo del tipo correcto dependiendo del tipo de instancia a la que se está asignando.nullptrse asigna a un puntero entero, unintse crea instanciación de tipo de la función de conversión de plantilla. Y lo mismo ocurre con los punteros de método también.nullptres un literal entero con valor cero, no puede usar su dirección, lo que logramos al eliminar & operador.¿Por qué necesitamos
nullptren primer lugar?NULLtiene algún problema con él como a continuación:1️⃣ Conversión implícita
2️⃣ Función que llama ambigüedad
3️⃣ Sobrecarga del constructor
String s((char*)0)).fuente
0 solía ser el único valor entero que podría usarse como un inicializador sin conversión para punteros: no puede inicializar punteros con otros valores enteros sin una conversión. Puede considerar 0 como un singleton consexpr sintácticamente similar a un literal entero. Puede iniciar cualquier puntero o entero. Pero sorprendentemente, encontrará que no tiene un tipo distinto: es un
int. Entonces, ¿cómo es que 0 puede inicializar punteros y 1 no? Una respuesta práctica fue que necesitamos un medio para definir el valor nulo del puntero y la conversión directa implícita deintun puntero es propenso a errores. Por lo tanto, 0 se convirtió en una verdadera bestia extraña y extraña de la era prehistórica.nullptrse propuso ser una representación constexpr real singleton de valor nulo para inicializar punteros. No se puede utilizar para inicializar directamente los enteros y elimina las ambigüedades relacionadas con la definiciónNULLen términos de 0.nullptrpodría definirse como una biblioteca que utiliza la sintaxis estándar pero parece que semánticamente es un componente central que falta.NULLahora está en desuso a favor denullptr, a menos que alguna biblioteca decida definirlo comonullptr.fuente
Aquí está el encabezado LLVM.
(se puede descubrir mucho con un rápido
grep -r /usr/include/*`)Una cosa que salta a la vista es la
*sobrecarga del operador (devolver 0 es mucho más amigable que segfaulting ...). Otra cosa es que no parece compatible con el almacenamiento de una dirección en absoluto . Lo cual, en comparación con la forma en que se lanza el vacío * y pasa los resultados NULL a los punteros normales como valores centinela, obviamente reduciría el factor "nunca olvidar, podría ser una bomba".fuente
NULL no necesita ser 0. Mientras use siempre NULL y nunca 0, NULL puede ser cualquier valor. Suponiendo que programe un microcontrolador von Neuman con memoria plana, que tenga sus interruptores en 0. Si NULL es 0 y algo escribe en un puntero NULL, el microcontrolador falla. Si NULL es digamos 1024 y en 1024 hay una variable reservada, la escritura no la bloqueará, y puede detectar asignaciones de puntero NULL desde dentro del programa. Esto no tiene sentido en las PC, pero para sondas espaciales, equipos militares o médicos es importante no chocar.
fuente