Pregunta

En los primeros días de C++ cuando se atornillan en la parte superior de C, no se podría utilizar NULL como fue definido como (void*)0.No se podía asignar NULL a cualquier puntero otros que void*, lo que hizo que tipo de inútil.En aquellos días, se aceptó que usted utiliza 0 (cero) para los punteros null.

A día de hoy, he continuado con la utilización de cero como un puntero nulo, pero a los que me rodean insistir en el uso de NULL.Yo personalmente no veo ningún beneficio para darle un nombre (NULL) a un valor existente - y ya que también me gusta probar punteros como valores de verdad:

if (p && !q)
  do_something();

a continuación, utilizando el cero tiene más sentido (como en el caso de que el uso de NULL, usted no puede, lógicamente, el uso de p && !q - usted necesita comparar explícitamente en contra de NULL, a menos que usted asuma NULL es cero, en cuyo caso, ¿por qué usar NULL).

¿Hay alguna razón objetiva para preferir cero en NULL (o viceversa), o es sólo una preferencia personal?

Editar:Debo añadir (y está diseñado para originalmente decir) que con RAII y excepciones, rara vez uso cero/NULL punteros, pero a veces se necesita de ellos todavía.

¿Fue útil?

Solución

Aquí está la opinión de Stroustrup sobre esto: Preguntas frecuentes sobre el estilo y la técnica de C ++

  

En C ++, la definición de NULL es 0, por lo que solo hay una diferencia estética. Prefiero evitar las macros, así que uso 0. Otro problema con nullptr es que las personas a veces creen erróneamente que es diferente de 0 y / o no un número entero. En el código pre-estándar, <=> fue / a veces se define como algo inadecuado y, por lo tanto, tuvo / debe evitarse. Eso es menos común en estos días.

     

Si tiene que nombrar el puntero nulo, llámelo <=>; así se llama en C ++ 11. Entonces, <=> será una palabra clave.

Dicho eso, no te preocupes por las cosas pequeñas.

Otros consejos

Hay un par de argumentos (uno de los cuales es relativamente reciente) que creo que contradicen Bjarne la posición de este.

  1. La documentación de la intención

El uso de NULL permite realizar búsquedas sobre su uso y también destaca que el desarrollador quería el uso de una NULL puntero, independientemente de si está siendo interpretado por el compilador como NULL o no.

  1. La sobrecarga de puntero y 'int' es relativamente raro

El ejemplo que todo el mundo cita es:

void foo(int*);
void foo (int);

void bar() {
  foo (NULL);  // Calls 'foo(int)'
}

Sin embargo, al menos en mi opinión, el problema con la anterior no es la que estamos usando NULL null puntero constante, es que tenemos sobrecargas de 'foo', que se toma muy en diferentes tipos de argumentos.El parámetro debe ser un int también, como cualquier otro tipo de resultado en una llamada ambigua y así generar una útil advertencia del compilador.

  1. Herramientas de análisis puede ayudar HOY mismo!

Incluso en la ausencia de C++ 0x, hay herramientas disponibles hoy en día que compruebe que NULL se utiliza para los punteros, y que 0 se utiliza para los tipos enteros.

  1. C++ 11 tendrá un nuevo std::nullptr_t tipo.

Este es el nuevo argumento a la mesa.El problema de la 0 y NULL está siendo atendido por C++ 0x, y usted puede garantizar que por cada aplicación que proporciona NULL, la primera cosa que va a hacer es:

#define NULL  nullptr

Para aquellos que utilizan NULL en lugar de 0, el cambio supondrá una mejora en la seguridad de tipos con poco o ningún esfuerzo, si hay algo que también puede coger un par de bugs donde se ha utilizado NULL para 0.Para cualquiera que utilice 0 el día de hoy....erm...bueno espero que tenga un buen conocimiento de las expresiones regulares...

Usar NULL. NULL muestra tu intención. Que es 0 es un detalle de implementación que no debería importar.

Dejé de usar NULL a favor de 0 hace mucho tiempo (así como la mayoría de las otras macros). Hice esto no solo porque quería evitar las macros tanto como sea posible, sino también porque NULL parece haberse usado en exceso en el código C y C ++. Parece que se usa siempre que se necesita un valor 0, no solo para punteros.

En proyectos nuevos, pongo esto en el encabezado del proyecto:

static const int nullptr = 0;

Ahora, cuando llegan los compiladores compatibles con C ++ 0x, todo lo que tengo que hacer es eliminar esa línea. Un buen beneficio de esto es que Visual Studio ya reconoce nullptr como una palabra clave y la resalta adecuadamente.

Siempre uso:

  • NULL para punteros
  • '\0' para caracteres
  • 0.0 para flotadores y dobles

donde 0 estaría bien. Es una cuestión de intención de señalización. Dicho esto, no soy anal al respecto.

    cerr << sizeof(0) << endl;
    cerr << sizeof(NULL) << endl;
    cerr << sizeof(void*) << endl;

    ============
    On a 64-bit gcc RHEL platform you get:
    4
    8
    8
    ================

La moraleja de la historia. Debería usar NULL cuando se trata de punteros.

1) Declara tu intención (no me hagas buscar en todo tu código tratando de averiguar si una variable es un puntero o algún tipo numérico).

2) En ciertas llamadas API que esperan argumentos variables, usarán un puntero NULL para indicar el final de la lista de argumentos. En este caso, usar un '0' en lugar de NULL puede causar problemas. En una plataforma de 64 bits, la llamada va_arg quiere un puntero de 64 bits, pero solo pasará un entero de 32 bits. ¿Me parece que estás confiando en que los otros 32 bits se pondrán a cero para ti? He visto ciertos compiladores (por ejemplo, el icpc de Intel) que no son tan amables, y esto ha resultado en errores de tiempo de ejecución.

Si recuerdo correctamente, NULL se define de manera diferente en los encabezados que he usado. Para C se define como (void *) 0, y para C ++ se define como solo 0. El código se parecía a:

#ifndef __cplusplus
#define NULL (void*)0
#else
#define NULL 0
#endif

Personalmente, sigo usando el valor NULL para representar punteros nulos, lo que hace explícito que está usando un puntero en lugar de algún tipo integral. Sí internamente, el valor NULL sigue siendo 0 pero no está representado como tal.

Además, no confío en la conversión automática de enteros a valores booleanos, sino que los comparo explícitamente.

Por ejemplo, prefiero usar:

if (pointer_value != NULL || integer_value == 0)

en lugar de:

if (pointer_value || !integer_value)

Baste decir que todo esto se soluciona en C ++ 11, donde uno puede simplemente usar nullptr en lugar de NULL, y también nullptr_t que es el tipo de un <=>.

Diría que la historia ha hablado y aquellos que argumentaron a favor del uso de 0 (cero) se equivocaron (incluido Bjarne Stroustrup). Los argumentos a favor de 0 fueron principalmente estéticos y & Quot; preferencia personal & Quot ;.

Después de la creación de C ++ 11, con su nuevo tipo nullptr, algunos compiladores comenzaron a quejarse (con parámetros predeterminados) sobre pasar 0 a funciones con argumentos de puntero, porque 0 no es un puntero.

Si el código se hubiera escrito usando NULL, una simple búsqueda y reemplazo podría haberse realizado a través de la base de código para convertirlo en nullptr. Si está atascado con el código escrito usando la opción de 0 como puntero, es mucho más tedioso actualizarlo.

Y si tiene que escribir un nuevo código ahora en el estándar C ++ 03 (y no puede usar nullptr), realmente debería usar NULL. Le facilitará mucho la actualización en el futuro.

Usualmente uso 0. No me gustan las macros, y no hay garantía de que algún encabezado de terceros que estés usando no redefina NULL para que sea algo extraño.

Puede usar un objeto nullptr según lo propuesto por Scott Meyers y otros hasta que C ++ obtenga una palabra clave nullptr:

const // It is a const object...
class nullptr_t 
{
public:
    template<class T>
    operator T*() const // convertible to any type of null non-member pointer...
    { return 0; }

    template<class C, class T>
    operator T C::*() const   // or any type of null member pointer...
    { return 0; }

private:
    void operator&() const;  // Can't take address of nullptr

} nullptr = {};

Google " nullptr " para más información.

Una vez trabajé en una máquina donde 0 era una dirección válida y NULL se definió como un valor octal especial. En esa máquina (0! = NULL), entonces código como

char *p;

...

if (p) { ... }

no funcionaría como esperabas. Tuviste que escribir

if (p != NULL) { ... }

Aunque creo que la mayoría de los compiladores definen NULL como 0 en estos días, todavía recuerdo la lección de hace años: NULL no es necesariamente 0.

Creo que el estándar garantiza que NULL == 0, por lo que puede hacerlo. Prefiero NULL porque documenta tu intención.

Usar 0 o NULL tendrá el mismo efecto.

Sin embargo, eso no significa que ambas sean buenas prácticas de programación. Dado que no hay diferencia en el rendimiento, elegir una opción de bajo nivel en lugar de una alternativa agnóstica / abstracta es una mala práctica de programación. Ayude a los lectores de su código a comprender su proceso de pensamiento .

NULL, 0, 0.0, '\ 0', 0x00 y whatelse se traducen en lo mismo, pero son entidades lógicas diferentes en su programa. Deben usarse como tales. NULL es un puntero, 0 es cantidad, 0x0 es un valor cuyos bits son interesantes, etc. No asignaría '\ 0' a un puntero si se compila o no.

Sé que algunas comunidades alientan a demostrar un conocimiento profundo de un entorno al romper los contratos del entorno. Sin embargo, los programadores responsables crean un código que se pueda mantener y mantienen tales prácticas fuera de su código.

Extraño, nadie, incluido Stroustroup, lo mencionó. Al hablar mucho sobre estándares y estética, nadie notó que es peligroso usar 0 en lugar de NULL, por ejemplo, en una lista de argumentos variables en la arquitectura donde sizeof(int) != sizeof(void*). Al igual que Stroustroup, prefiero <=> por razones estéticas, pero hay que tener cuidado de no usarlo donde su tipo pueda ser ambiguo.

Intento evitar toda la pregunta utilizando referencias de C ++ siempre que sea posible. En lugar de

void foo(const Bar* pBar) { ... }

a menudo puedes escribir

void foo(const Bar& bar) { ... }

Por supuesto, esto no siempre funciona; pero los punteros nulos se pueden usar en exceso.

Estoy con Stroustrup en este :-) Como NULL no es parte del lenguaje, prefiero usar 0.

Principalmente preferencia personal, aunque uno podría argumentar que NULL hace que sea bastante obvio que el objeto es un puntero que actualmente no apunta a nada, por ejemplo

void *ptr = &something;
/* lots o' code */
ptr = NULL; // more obvious that it's a pointer and not being used

IIRC, el estándar no requiere que NULL sea 0, por lo que usar lo que esté definido en < stddef.h > es probablemente el mejor para tu compilador.

Otra faceta del argumento es si debe usar comparaciones lógicas (conversión implícita a bool) o verificación de explicidad contra NULL, pero eso también se reduce a la legibilidad.

Prefiero usar NULL, ya que deja en claro que su intención es que el valor represente un puntero, no un valor aritmético. El hecho de que sea una macro es desafortunado, pero como está muy arraigado, hay poco peligro (a menos que alguien haga algo realmente descabellado). Desearía que fuera una palabra clave desde el principio, pero ¿qué puedes hacer?

Dicho esto, no tengo ningún problema con el uso de punteros como valores de verdad en sí mismos. Al igual que con NULL, es un idioma arraigado.

C ++ 09 agregará la construcción nullptr, que creo que hace mucho tiempo.

Siempre uso 0. No por ninguna razón real, solo porque cuando estaba aprendiendo C ++ por primera vez, leí algo que me recomendó usar 0 y siempre lo hice de esa manera. En teoría, podría haber un problema de confusión en la legibilidad, pero en la práctica nunca me he encontrado con un problema de este tipo en miles de horas hombre y millones de líneas de código. Como dice Stroustrup, en realidad es solo un problema estético personal hasta que el estándar se convierte en nulo.

Alguien me lo dijo una vez ... voy a redefinir NULL a 69. Desde entonces no lo uso: P

Hace que su código sea bastante vulnerable.

Edición :

No todo en el estándar es perfecto. La macro NULL es una constante de puntero nulo C ++ definida por la implementación que no es totalmente compatible con la macro C NULL, lo que además del tipo de ocultación implícita la convierte en una herramienta inútil y propensa a errores.

NULL no se comporta como un puntero nulo sino como un literal O / OL.

Dime que el siguiente ejemplo no es confuso:

void foo(char *); 
void foo(int); 
foo(NULL); // calls int version instead of pointer version! 

Es por todo eso, en el nuevo estándar aparece std :: nullptr_t

Si no quiere esperar al nuevo estándar y quiere usar un nullptr, use al menos uno decente como el propuesto por Meyers (vea el comentario de jon.h).

Bueno, defiendo no utilizar punteros 0 o NULL siempre que sea posible.

Usarlos tarde o temprano conducirá a fallas de segmentación en su código. En mi experiencia esto, y los punteros en gereral son una de las mayores fuentes de errores en C ++

también, conduce a " if-not-null " declaraciones en todo su código. Mucho mejor si puede confiar siempre en un estado válido.

Casi siempre hay una mejor alternativa.

Establecer un puntero a 0 simplemente no está tan claro. Especialmente si vienes un lenguaje que no sea C ++. Esto incluye C y Javascript.

Recientemente delté con un código como este:

virtual void DrawTo(BITMAP *buffer) =0;

para la función virtual pura por primera vez. Pensé que sería un jiberjash mágico durante una semana. Cuando me di cuenta de que básicamente estaba configurando el puntero de función a null (ya que las funciones virtuales son solo punteros de función en la mayoría de los casos para C ++) me pateé.

virtual void DrawTo(BITMAP *buffer) =null;

habría sido menos confuso que esa basterdación sin el espacio adecuado para mis nuevos ojos. En realidad, me pregunto por qué C ++ no emplea minúsculas <=> al igual que ahora usa minúsculas falso y verdadero ahora.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top