¿Qué es la palabra clave nullptr y por qué es mejor que NULL?

Resuelto Khaled Alshaya asked hace 15 años • 14 respuestas

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 nullptrfunciona. 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 nullptrsea superior al antiguo 0?

Khaled Alshaya avatar Aug 15 '09 23:08 Khaled Alshaya
Aceptado

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

Esto no es sorprendente. Ambos truey falseson palabras clave y como literales tienen un tipo ( bool). nullptres un puntero literal de tipo std::nullptr_ty es un valor pr (no puede tomar su dirección usando &).

  • 4.10acerca de la conversión de puntero dice que un valor pr de tipo std::nullptr_tes una constante de puntero nulo y que una constante de puntero nulo integral se puede convertir a std::nullptr_t. No se permite la dirección contraria. Esto permite sobrecargar una función tanto para punteros como para números enteros, y pasarla nullptrpara seleccionar la versión del puntero. Pasando NULLo 0seleccionaría de manera confusa la intversión.

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

  • La Norma exige que sizeof(nullptr_t)sea sizeof(void*).

Johannes Schaub - litb avatar Aug 15 '2009 17:08 Johannes Schaub - litb

¿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 nullptrcuando lo hubiera usado NULLen el pasado.

(Mis palabras):

Por último, no olvides que nullptres un objeto: una clase. Se puede usar en cualquier lugar NULLdonde 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 typedefde decltype(nullptr), como se muestra aquí:

Definido en el encabezado <cstddef>:

Ver:

  1. https://en.cppreference.com/w/cpp/types/nullptr_t
  2. 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:

  1. Cprogramming.com: Mejores tipos en C++ 11: nullptr, clases enum (enumeración fuertemente tipada) y cstdint
  2. https://en.cppreference.com/w/cpp/language/decltype
  3. https://en.cppreference.com/w/cpp/types/nullptr_t
  4. https://en.cppreference.com/w/cpp/header/cstddef
  5. https://en.cppreference.com/w/cpp/keyword/using
  6. https://en.cppreference.com/w/cpp/keyword/typedef
Gabriel Staples avatar Mar 07 '2018 06:03 Gabriel Staples

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
nik avatar Aug 15 '2009 17:08 nik

Cuando tienes una función que puede recibir punteros a más de un tipo, llamarla NULLes 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_tlo 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)  {  }
Motti avatar Aug 16 '2009 06:08 Motti