Motivo por el que no se tiene una macro DELETE para C ++

¿Hay alguna buena razón (excepto “las macros son malas”, quizás) para NO utilizar las siguientes macros?

#define DELETE( ptr ) \ if (ptr != NULL) \ { \ delete ptr; \ ptr = NULL; \ } #define DELETE_TABLE( ptr ) \ if (ptr != NULL) \ { \ delete[] ptr; \ ptr = NULL; \ } 

Personalmente prefiero lo siguiente

 template< class T > void SafeDelete( T*& pVal ) { delete pVal; pVal = NULL; } template< class T > void SafeDeleteArray( T*& pVal ) { delete[] pVal; pVal = NULL; } 

Ellos comstackn hasta EXACTAMENTE el mismo código al final.

Puede haber alguna forma extraña de romper el sistema #define, pero, personalmente (y esto probablemente me hará gemir;) No creo que sea un gran problema.

Porque en realidad no resuelve muchos problemas.

En la práctica, la mayoría de los problemas de acceso al puntero colgando provienen del hecho de que existe otro puntero al mismo objeto en otra parte del progtwig y luego se utiliza para acceder al objeto que se ha eliminado.

Poner a cero uno de un número desconocido de copias de puntero puede ayudar un poco, pero generalmente este es un puntero que está a punto de salirse del scope, o configurarlo para apuntar a un nuevo objeto en cualquier caso.

Desde un punto de vista de diseño, llamar manualmente delete o delete[] debería ser relativamente raro. Usar objetos por valor en lugar de objetos asignados dinámicamente cuando corresponda utilizando std::vector lugar de matrices dinámicamente asignadas y ajustar la propiedad de los objetos que tienen que asignarse dinámicamente en un puntero inteligente apropiado (por ejemplo, auto_ptr , scoped_ptr o shared_ptr ) para administrar su vida útil son todos los enfoques de diseño que hacen que reemplazar reemplazar y delete[] con una macro “más segura” sea un enfoque de beneficio comparativamente bajo.

Porque está bien eliminar un puntero NULL(0) . No es necesario verificar si el puntero en realidad es NULL(0) o no. Si desea establecer el puntero a NULL, después de eliminar, puede sobrecargar el operador de delete global sin utilizar macros.


Parece que estaba equivocado sobre el segundo punto:

Si desea establecer el puntero a NULL, después de eliminarlo, puede sobrecargar el operador de delete globalmente

El problema es que si sobrecargas el global new y lo delete , podrías tener algo como esto:

 void* operator new(size_t size) { void* ptr = malloc(size); if(ptr != 0) { return ptr; } throw std::bad_alloc("Sorry, the allocation didn't go well!"); } void operator delete(void* p) { free(p); p = 0; } 

Ahora, si configura p = 0; en la delete sobrecargada, en realidad está configurando la local , pero no la p original. Básicamente, estamos obteniendo una copia del puntero en la delete sobrecargada.

Lo siento, estaba en la cima de mi cabeza, lo pensé un segundo ahora. De todos modos, escribiría la función en línea de la plantilla para hacer la cosa en vez de escribir MACROS MALOS 🙂

Porque DELETE ya está definido en winnt.h:

#define DELETE (0x00010000L)

  • eliminar aceptar un puntero NULL sin problema, por lo que las pruebas son superfluas.
  • restablecer el puntero a NULL no siempre es posible, por lo que no se pueden usar sistemáticamente.
  • la seguridad que brindan es ilusoria: según mi experiencia, la mayoría de los problemas con los punteros colgantes provienen de indicadores distintos a los que se usan para eliminar.

Su macro falla por varias razones:

  • Es un macro. No respeta las reglas de scope ni otras características del lenguaje, lo que facilita el uso incorrecto.
  • Puede causar errores de comstackción: DELETE (getPtr()); no se comstackrá, porque no puede configurar la llamada a la función para anular. O si el puntero es const, tu macro también fallará.
  • No logra nada. delete NULL está permitido por el estándar.

Finalmente, como dijo Grimner, estás tratando de resolver un problema que no debería existir en primer lugar. ¿Por qué estás llamando manualmente a borrar? `¿No usas los contenedores de la biblioteca estándar? ¿Punteros inteligentes? ¿Asignación de stack? RAII?

Como dijo Stroustrup anteriormente, la única forma de evitar memory leaks es evitar tener que llamar a eliminar.

  1. borrar un puntero nulo no hace nada, por lo que no es necesario verificar si el puntero es nulo antes de la eliminación. Anular el puntero borrado puede ser necesario (pero no en todos los casos).

  2. Se deben evitar las macros tanto como sea posible, ya que son difíciles de depurar, mantener, introducir posibles efectos secundarios, no son parte de espacios de nombres, etc.

  3. borrar un puntero que no fue dinámicamente asignado con nuevo seguirá siendo un problema …

  1. Las macros son malvadas ¿Por qué no usar las funciones en plantilla en línea?
  2. Puede eliminar ptrs nulos.
  3. En muchos casos, no es necesario configurar ptr como nulo: destructores, por ejemplo.
  1. las macros son malvadas : p En serio, considere usar funciones de template línea en su lugar
  2. establecer un puntero a NULL después de la desasignación tiende a enmascarar errores
  3. alienta if (ptr != NULL) comprueba como un mecanismo de control de flujo. Personalmente, considero que este código huele a lo largo de las líneas de void foo(int arg) siendo reemplazado por void foo(int arg, bool doAdvancedThings=false)
  4. fomenta el uso de punteros crudos en la memoria que debe borrarse – shared_ptr y sus parientes siempre deben usarse para la propiedad, los punteros sin formato se pueden usar para otros accesos
  5. anima a mirar una variable de puntero después de la desasignación, incluso peor if (ptr != NULL) usa if (ptr != NULL) lugar de if (ptr) … la comparación de punteros es otro olor a código

Use boost :: shared_ptr <> en su lugar.

http://www.boost.org/doc/libs/1_39_0/libs/smart_ptr/shared_ptr.htm

El MACRO aquí proporciona algunas de las funcionalidades que probablemente esté buscando.

Sí, nunca debes llamar a eliminar directamente. Utilice shared_ptr, scoped_ptr, unique_ptr o el puntero inteligente que tenga en su proyecto.

  1. No te da mucho beneficio. Eliminar un puntero nulo es inofensivo, por lo que el único beneficio es configurar el puntero a NULL después de la eliminación. Si un desarrollador puede recordar llamar a su macro en lugar de eliminar, también puede recordar anular el puntero, por lo que realmente no se está protegiendo de un desarrollador descuidado. Los únicos beneficios es que esto sucede en dos líneas en lugar de una.
  2. Es potencialmente confuso. Eliminar es una parte estándar del lenguaje. Su función de macro o plantilla no. Por lo tanto, un desarrollador nuevo deberá buscar esa definición de macro para comprender qué está haciendo su código.

En mi opinión, el beneficio no supera el costo.