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 nullptr
funciona. 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 nullptr
es superior a los buenos viejos 0
?
nullptr
también se utiliza para representar referencias nulas para identificadores administrados en C ++ / CLI.nullptr_t
garantiza 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_t
se puede instanciar, pero todas las instancias serán idénticasnullptr
porque 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
true
yfalse
son palabras clave y como literales tienen un tipo (bool
).nullptr
es un puntero literal de tipostd::nullptr_t
, y es un prvalue (no puede tomar la dirección usando&
).4.10
acerca de la conversión de puntero dice que un valor de tipostd::nullptr_t
es 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 pasarnullptr
para seleccionar la versión del puntero. PasandoNULL
o0
seleccionaría confusamente laint
versión.Un molde de
nullptr_t
un tipo integral necesita unreinterpret_cast
, y tiene la misma semántica que un molde de(void*)0
un tipo integral (implementación de mapeo definida). Areinterpret_cast
no se puede convertirnullptr_t
a 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.NULL
ni siquiera se garantiza que sea0
. Puede ser0L
, en cuyo caso una llamada avoid f(int); void f(char *);
será ambigua.nullptr
siempre favorecerá la versión de puntero, y nunca llamará a la versiónint
. También tenga en cuenta quenullptr
es convertible abool
(el borrador dice que en4.12
).int
versión. Perof(0L)
es ambiguo, porquelong -> int
tambiénlong -> void*
es igualmente costoso. Entonces, si NULL está0L
en su compilador, entonces una llamadaf(NULL)
será ambigua dadas esas dos funciones. No es así, pornullptr
supuesto.(void*)0
en C ++. Pero se puede definir como cualquier constante de puntero nulo arbitrario, que cualquier constante integral con valor 0 ynullptr
cumplir. 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:
template
fuente
¿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
nullptr
es un objeto, una clase. Se puede usar en cualquier lugar dondeNULL
se 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 unatypedef
dedecltype(nullptr)
.Referencias
fuente
Cuando tiene una función que puede recibir punteros a más de un tipo, llamarlo con
NULL
es ambiguo. La forma en que esto se soluciona ahora es muy hacky al aceptar un int y asumir que esNULL
.En
C++11
sería capaz de sobrecargarse, pornullptr_t
lo queptr<T> p(42);
sería un error en tiempo de compilación en lugar de un tiempo de ejecuciónassert
.fuente
NULL
se define como0L
?nullptr
no se puede asignar a un tipo integral como, por ejemplo, unint
tipo de puntero; ya sea un tipo de puntero incorporado comoint *ptr
o un puntero inteligente comostd::shared_ptr<T>
Creo que esta es una distinción importante porque
NULL
todavía se puede asignar tanto a un tipo integral como a un puntero, ya queNULL
es una macro expandida a la0
que puede servir tanto como un valor inicial para unint
puntero como para un puntero.fuente
NULL
no 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
None
generalmente se usa para algo que no se ha inicializado, pero al mismo tiempo comparaciones comoNone == 0
son falsas.Por otro lado, en C simple,
NULL == 0
devolvería IIRC verdadero porqueNULL
es solo una macro que devuelve 0, que siempre es una dirección no válida (AFAIK).fuente
NULL
es 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_t
nullptr
es 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.nullptr
se asigna a un puntero entero, unint
se 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.nullptr
es un literal entero con valor cero, no puede usar su dirección, lo que logramos al eliminar & operador.¿Por qué necesitamos
nullptr
en primer lugar?NULL
tiene 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 deint
un 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.nullptr
se 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ónNULL
en términos de 0.nullptr
podría definirse como una biblioteca que utiliza la sintaxis estándar pero parece que semánticamente es un componente central que falta.NULL
ahora 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