¿Qué es la palabra clave nullptr y por qué es mejor que NULL?
Ahora tenemos C++11 con muchas características nuevas. Uno interesante y confuso (al menos para mí) es el nuevo nullptr
.
Bueno, ya no hay necesidad de esa desagradable macro NULL
.
int* x = nullptr;
myclass* obj = nullptr;
Aún así, no entiendo cómo nullptr
funciona. Por ejemplo, un artículo de Wikipedia dice:
C++ 11 corrige esto introduciendo una nueva palabra clave que sirve como constante de puntero nulo distinguido: nullptr. Es de 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 ni comparable a 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
sea superior al antiguo 0
?
¿Cómo es una palabra clave y una instancia de un tipo?
Esto no es sorprendente. Ambos true
y false
son palabras clave y como literales tienen un tipo ( bool
). nullptr
es un puntero literal de tipo std::nullptr_t
y es un valor pr (no puede tomar su dirección usando &
).
4.10
acerca de la conversión de puntero dice que un valor pr de tipostd::nullptr_t
es una constante de puntero nulo y que una constante de puntero nulo integral se puede convertir astd::nullptr_t
. No se permite la dirección contraria. Esto permite sobrecargar una función tanto para punteros como para números enteros, y pasarlanullptr
para seleccionar la versión del puntero. PasandoNULL
o0
seleccionaría de manera confusa laint
versión.Una conversión de
nullptr_t
un tipo integral necesita areinterpret_cast
y tiene la misma semántica que una conversión 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 utilicestatic_cast
.La Norma exige que
sizeof(nullptr_t)
seasizeof(void*)
.
¿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 está en negrita):
...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ás pasando lo que parece ser un puntero), ¡en realidad es la primera función la que se llamará! El problema es que debido a que NULL es 0 y 0 es un número entero, se llamará a la primera versión de func. Este es el tipo de cosas que, sí, no suceden todo el tiempo, pero cuando suceden, son extremadamente frustrantes y confusas. Si no conocía los detalles de lo que está pasando, bien podría parecer un error del compilador. Una característica del lenguaje que parece un error del compilador no es algo que desee.
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 escribiera NULL antes, debería usar nullptr en su lugar. No está más claro para usted, el programador , (todos saben lo que significa NULL), pero es más explícito para el compilador , que ya no verá ceros en todas partes para que tengan un significado especial cuando se usan como puntero.
Allain termina su artículo con:
Independientemente de todo esto, la regla general para C++ 11 es simplemente comenzar a usarlo
nullptr
cuando lo hubiera usadoNULL
en el pasado.
(Mis palabras):
Por último, no olvides que nullptr
es un objeto: una clase. Se puede usar en cualquier lugar NULL
donde se usó antes, pero si necesita su tipo por algún motivo, su tipo se puede extraer con decltype(nullptr)
o describir directamente como std::nullptr_t
, que es simplemente un typedef
de decltype(nullptr)
, como se muestra aquí:
Definido en el encabezado <cstddef>
:
Ver:
- https://en.cppreference.com/w/cpp/types/nullptr_t
- y https://en.cppreference.com/w/cpp/header/cstddef
namespace std
{
typedef decltype(nullptr) nullptr_t; // (since C++11)
// OR (same thing, but using the C++ keyword `using` instead of the C and C++
// keyword `typedef`):
using nullptr_t = decltype(nullptr); // (since C++11)
} // namespace std
Referencias:
- Cprogramming.com: Mejores tipos en C++ 11: nullptr, clases enum (enumeración fuertemente tipada) y cstdint
- https://en.cppreference.com/w/cpp/language/decltype
- https://en.cppreference.com/w/cpp/types/nullptr_t
- https://en.cppreference.com/w/cpp/header/cstddef
- https://en.cppreference.com/w/cpp/keyword/using
- https://en.cppreference.com/w/cpp/keyword/typedef
De nullptr: un puntero nulo claro y con seguridad de tipos :
La nueva palabra clave nullptr de C++09 designa una constante rvalue que sirve como un literal de puntero nulo universal, reemplazando el literal 0 con errores y de tipo débil y la infame macro NULL. nullptr pone así fin a más de 30 años de vergüenza, ambigüedad y errores. Las siguientes secciones presentan la función nullptr y muestran cómo puede remediar los problemas de NULL y 0.
Otras referencias:
- WikiBooks , con código de muestra.
- Aquí en Stack Overflow: ¿Utiliza NULL o 0 (cero) para punteros en C++?
template
- Grupo de Google: comp.lang.c++.moderated - discusión sobre el compilador
Cuando tienes una función que puede recibir punteros a más de un tipo, llamarla NULL
es ambiguo. La forma en que se soluciona esto ahora es muy complicada al aceptar un int y asumir 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 este caso C++11
, podría sobrecargar, por nullptr_t
lo que ptr<T> p(42);
sería un error en tiempo de compilación en lugar de un error en tiempo de ejecución assert
.
ptr(std::nullptr_t) : p_(nullptr) { }