que not declared c++ pointers c++11 nullptr

c++ - not - ¿Qué es exactamente nullptr?



nullptr vs null (11)

Ahora tenemos C ++ 11 con muchas características nuevas. Una interesante y confusa (al menos para mí) es la nueva nullptr .

Bueno, ya no es necesario para la desagradable macro NULL .

int* x = nullptr; myclass* obj = nullptr;

Aún así, no entiendo cómo funciona nullptr . Por ejemplo, el artículo de Wikipedia dice:

C ++ 11 corrige esto introduciendo una nueva palabra clave que sirve como una constante de puntero nula distinguida: nullptr. Es de tipo nullptr_t , que es convertible implícitamente y comparable a cualquier tipo de puntero o tipo puntero a miembro. No es implícitamente convertible o comparable a los tipos integrales, excepto para bool.

¿Cómo es una palabra clave y una instancia de un tipo?

Además, ¿tienes otro ejemplo (al lado de Wikipedia) donde nullptr es superior al buen viejo 0 ?


¿Cómo es una palabra clave y una instancia de un tipo?

Esto no es sorprendente. Tanto true como false son palabras clave y como literales tienen un tipo ( bool ). nullptr es un puntero literal de tipo std::nullptr_t , y es un prvalue (no puede tomar su dirección usando & ).

  • 4.10 sobre la conversión de punteros dice que un prvalue de tipo std::nullptr_t es una constante de puntero nula, y que una constante de puntero nula integral se puede convertir a std::nullptr_t . La dirección opuesta no está permitida. Esto permite sobrecargar una función tanto para punteros como para enteros, y pasar nullptr para seleccionar la versión del puntero. Pasar NULL o 0 seleccionaría confusamente la versión int .

  • Una nullptr_t de nullptr_t a un tipo integral necesita un reinterpret_cast y tiene la misma semántica que una conversión de (void*)0 a un tipo integral (implementación de mapeo definida). Un reinterpret_cast no puede convertir nullptr_t a ningún tipo de puntero. Confíe en la conversión implícita si es posible o utilice static_cast .

  • El Estándar requiere que sizeof(nullptr_t) sea sizeof(void*) .


Además, ¿tienes otro ejemplo (al lado de Wikipedia) donde nullptr es superior al buen viejo 0?

Sí. 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 compilar de forma cruzada a una plataforma con un ancho de registro diferente (todavía no estoy seguro de por qué solo al compilar de forma cruzada de x86_64 a x86, advierte a la warning: converting to non-pointer type ''int'' from NULL ) :

Considere este código (C ++ 03):

#include <iostream> struct B {}; struct A { operator B*() {return 0;} operator bool() {return true;} }; int main() { A a; B* pb = 0; typedef void* null_ptr_t; null_ptr_t null = 0; std::cout << "(a == pb): " << (a == pb) << std::endl; std::cout << "(a == 0): " << (a == 0) << std::endl; // no warning std::cout << "(a == NULL): " << (a == NULL) << std::endl; // warns sometimes std::cout << "(a == null): " << (a == null) << std::endl; }

Se obtiene esta salida:

(a == pb): 1 (a == 0): 0 (a == NULL): 0 (a == null): 1


¿Por qué nullptr en C ++ 11? ¿Qué es? ¿Por qué NULL no es suficiente?

El experto en C ++ Alex Allain lo dice perfectamente aquí :

"... imagina que tienes las siguientes dos declaraciones de funciones:

void func(int n); void func(char *s); func( NULL ); // guess which function gets called?

Aunque parece que se llamará a la segunda función, después de todo, está pasando lo que parece ser un puntero, ¡es realmente la primera función a la que se llamará! El problema es que debido a que NULL es 0 y 0 es un entero, se llamará a la primera versión de func. Este es el tipo de cosas que, sí, no sucede todo el tiempo, pero cuando sucede, es extremadamente frustrante y confuso. Si no conocía los detalles de lo que está sucediendo, podría parecer un error de compilación. Una característica del lenguaje que se parece a un error del compilador es, bueno, no es algo que quieras.

Introduzca nullptr. En C ++ 11, nullptr es una nueva palabra clave que puede (y debe!) Usarse para representar punteros NULL; en otras palabras, dondequiera que estuvieras escribiendo NULL antes, deberías usar nullptr en su lugar. El programador no lo tiene más claro (todo el mundo sabe lo que significa NULL), pero es más explícito para el compilador , que ya no verá 0s en todas partes para tener un significado especial cuando se usa como puntero ".


0 solía ser el único valor entero que podría usarse como un inicializador sin conversión para los punteros: no puede inicializar los punteros con otros valores enteros sin una conversión. Puede considerar 0 como un consexpr singleton sintácticamente similar a un entero literal. Puede iniciar cualquier puntero o entero. Pero, sorprendentemente, encontrará que no tiene un tipo distinto: es un int . Entonces, ¿cómo 0 puede inicializar punteros y 1 no puede? Una respuesta práctica fue que necesitamos un medio para definir el valor nulo del puntero y la conversión implícita directa de int a un puntero es propensa a errores. Así, 0 se convirtió en una verdadera bestia extraña y extraña de la era prehistórica. nullptr se propuso ser una representación real de singleton constexpr de valor nulo para inicializar punteros. No se puede usar para inicializar directamente enteros y elimina las ambigüedades involucradas con la definición de NULL en términos de 0. nullptr podría definirse como una biblioteca que utiliza la sintaxis estándar, pero se considera semánticamente como un componente central faltante. NULL ahora está en desuso a favor de nullptr , a menos que alguna biblioteca decida definirlo como nullptr .


Bueno, otros idiomas tienen palabras reservadas que son instancias de tipos. Python, por ejemplo:

>>> None = 5 File "<stdin>", line 1 SyntaxError: assignment to None >>> type(None) <type ''NoneType''>

En realidad, esta es una comparación bastante cercana porque None se usa normalmente para algo que no se ha inicializado, pero al mismo tiempo las comparaciones como None == 0 son falsas.

Por otro lado, en el plano C, NULL == 0 devolverá el IIRC verdadero porque NULL es solo una macro que devuelve 0, que siempre es una dirección no válida (AFAIK).


Cuando tiene una función que puede recibir punteros a más de un tipo, llamarla con NULL es ambiguo. La forma en que se soluciona esto ahora es muy complicada al aceptar un int y suponer que es NULL .

template <class T> class ptr { T* p_; public: ptr(T* p) : p_(p) {} template <class U> ptr(U* u) : p_(dynamic_cast<T*>(u)) { } // Without this ptr<T> p(NULL) would be ambiguous ptr(int null) : p_(NULL) { assert(null == NULL); } };

En C++11 podría sobrecargarse en nullptr_t para que ptr<T> p(42); sería un error en tiempo de compilación en lugar de una aserción en tiempo de ejecución.

ptr(std::nullptr_t) : p_(nullptr) { }


De nullptr: Un puntero nulo de tipo seguro y claro :

La nueva palabra clave nullptr de C ++ 09 designa una constante rvalue que sirve como un literal de puntero nulo universal, que reemplaza el 0 y el literal 0 de tipo débil y la infame macro NULL. nullptr pone fin a más de 30 años de vergüenza, ambigüedad y errores. Las siguientes secciones presentan la facilidad nullptr y muestran cómo puede remediar las enfermedades de NULL y 0.

Otras referencias:


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 usó NULL (es decir, el valor 0), debería llamar al sobrecargado para int:

void f(int); void f(char*); void g() { f(0); // Calls f(int). f(NULL); // Equals to f(0). Calls f(int). }

Esto probablemente no es lo que querías. C ++ 11 resuelve esto con nullptr; Ahora puedes escribir lo siguiente:

void g() { f(nullptr); //calls f(char*) }


Es una palabra clave porque el estándar lo especificará como tal. ;-) Según el último borrador público (n2914)

2.14.7 literales de puntero [lex.nullptr]

pointer-literal: nullptr

El puntero literal es la palabra clave nullptr . Es un valor de tipo std::nullptr_t .

Es útil porque no se convierte implícitamente en un valor integral.


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 tiene sus vectores de interrupción 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 las sondas espaciales, el equipo militar o médico es importante no bloquearse.


nullptr no se puede asignar a un integral type como un int, sino solo un pointer tipo; ya sea un tipo de puntero incorporado como int *ptr o un puntero inteligente como std::shared_ptr<T>

Creo que esta es una distinción importante porque NULL todavía puede asignarse a un integral type y un pointer como NULL es una macro expandida a 0 que puede servir como valor inicial para un int así como un pointer .