2009-02-12 11 views
5
#define SAFE_DELETE(a) if((a) != NULL) delete (a); (a) = NULL; 

O¿Qué versión de safe_delete es mejor?

template<typename T> void safe_delete(T*& a) { 
    delete a; 
    a = NULL; 
} 

o cualquier otra forma mejor

+3

sigue siendo una tontería, pero la eliminación segura de macros debe ser: #define SAFE_DELETE (a) do {delete (a); (a) = NULO; } while (0) –

Respuesta

5

Claramente la función, por una razón simple. La macro evalúa su argumento varias veces. Esto puede tener efectos secundarios malvados. También la función puede ser delimitada. Nada mejor que eso :)

5

En general, prefieren las funciones en línea sobre las macros, como macros no respetan alcance, y pueden entrar en conflicto con algunos símbolos durante el procesamiento previo, lo que lleva a muy extraños errores de compilación.

Por supuesto, a veces las plantillas y funciones no funcionan, pero aquí no es el caso.

Además, la mejor eliminación segura no es necesaria, ya que podría utilizar smart-pointers, por lo tanto, no es necesario recordar el uso de este método en el código del cliente, sino encapsularlo.

(edición) Como otros han señalado, caja eliminar no es seguro, ya que incluso si alguien hace no se olvide de utilizar, todavía puede no tener el efecto deseado. Por lo tanto, en realidad es completamente inútil, porque el uso de safe_delete correctamente requiere más reflexión que el simple ajuste a 0 por uno mismo.

7

borrar a;

ISO C++ especifica que eliminar en un puntero NULL simplemente no hace nada.

Presupuesto de 14882 ISO:

 
    5.3.5 Delete [expr.delete] 

    2 [...] In either alternative, if the value of the operand of delete is the 
     null pointer the operation has no effect. [...] 

Saludos, Bodo

/editar: No me di cuenta del a = NULL; en la publicación original, nueva versión: eliminar a; a = NULL; sin embargo, el problema con establecer a = NULL ya ha sido señalado (falsa sensación de seguridad).

+0

Acerca de las pruebas de rendimiento y NULL: sé que se podría llamar a la eliminación con NULL, pero if (p! = NULL) es una operación de lectura rápida que podría omitir una llamada de función y una asignación (escribir en memoria). Eliminar el if no está mal, pero ¿qué pasa con los programadores junior que lo leen y qué pasa con el rendimiento? –

+0

Es verdad, por otro lado: la prueba para NULL es un salto condicional. Si escribe su código de una manera, que normalmente no libera punteros NULL, solo duplica ese salto condicional, porque lo hace usted mismo y luego llama a una función de todos modos, eso lo hace de nuevo. Entonces, en mi opinión, es mejor enseñar a hacer un seguimiento de recursos adecuado que hacer pruebas NULL. –

2

No es necesario que pruebe la nulidad con delete, es equivalente a una operación nula. (a) = NULL me hace levantar una ceja. La segunda opción es mejor.

Sin embargo, si tiene una opción, debe utilizar punteros inteligentes, como std::auto_ptr o tr1::shared_ptr, que ya lo hacen por usted.

+0

Ni auto_ptr ni shared_ptr se establece en NULL en la eliminación. QPointer es la única clase que sé que lo hace. –

19

Yo diría que ninguno, ya que ambos le darán una falsa sensación de seguridad. Por ejemplo, suponga que tiene una función:

void Func(SomePtr * p) { 
    // stuff 
    SafeDelete(p); 
} 

Se establece p NULL, pero las copias de p fuera de la función está afectada.

Sin embargo, si debe hacer esto, vaya con la plantilla: las macros siempre tendrán la posibilidad de tocar otros nombres.

+0

Bueno, un tipo loco -1 está al acecho. Arriba uno. Esta respuesta es correcta ... – gimpf

+3

+1 Establecer un puntero a NULL después de eliminarlo rara vez tiene sentido. –

+0

La configuración de un puntero (miembro de una clase) en NULL después de la eliminación podría valer la pena el tiempo empleado para agregar la línea a la función de plantilla o el par de ciclos de la CPU desperdiciados. Si tiene que cavar en un código creado por otra persona con un diseño deficiente que pueda detectar fácilmente (estrellarse) un monstruo bien escondido: objetos que utilizan objetos ya eliminados durante una décima de segundo. Si no estás usando un Z80, vale la pena. Salvará tu cabeza para explotar. –

2

creo

#define SAFE_DELETE(pPtr) { delete pPtr; pPtr = NULL } es mejor

  1. su autorización para llamar a eliminar Con PPTR es NULL.Entonces si no es necesario.
  2. en caso de que si llamas a SAFE_DELETE (ptr + i), se producirá un error de compilación.
  3. La definición de la plantilla creará varias instancias de la función para cada tipo de datos. En mi opinión, en este caso, estas múltiples definiciones no agregan ningún valor.
  4. Además, con la definición de la función de plantilla, tiene una sobrecarga de llamada de función.
+1

# 4 es realmente un no problema. Una función tan trivial seguramente se verá reflejada en cualquier compilador medio decente. – Dan

+1

# 3 no es un problema por la misma razón. De hecho, creo que el # 2 también lo es, ya que ptr + 1 no es un valor de l. Entonces, básicamente, todos los puntos relevantes no eran válidos. –

+1

Addidionalmente, si uno quisiera hacer esto con una macro, al menos debería usar esto: #define save_delete (p) do {delete p; p = NULL; } while (0) Piénselo, si aún no ha visto una construcción así;) –

0

Como se ha mencionado un poco más arriba, el segundo es el mejor, no una macro con potenciales efectos secundarios no deseados, no tiene el cheque que no sean necesarios contra NULL (aunque sospecho que está haciendo que, como un tipo de verificar), etc. Pero ninguno promete seguridad. Si usa algo como tr1 :: smart_ptr, asegúrese de leer los documentos y asegúrese de que tenga la semántica correcta para su tarea. Recientemente tuve que buscar y limpiar una gran pérdida de memoria debido a que un compañero de trabajo puso smart_ptrs en una estructura de datos con enlaces circulares :) (debería haber usado weak_ptrs para referencias)

0

Aparece realmente el uso de SAFE_DELETE ser un enfoque de programadores C para controlar la administración de memoria integrada en C++. Mi pregunta es: ¿C++ permitirá este método de usar un SAFE_DELETE en los punteros que se han encapsulado correctamente como Privado? ¿Esta macro SÓLO funcionaría en el puntero que se declara pública? OOP BAD !!

0

prefiero esta versión:

~scoped_ptr() { 
    delete this->ptr_; //this-> for emphasis, ptr_ is owned by this 
} 

Ajuste del puntero nulo después de borrar que es bastante inútil, ya que la única razón por la que utilizaría punteros es permitir que un objeto que se hace referencia en varios lugares a la vez . Incluso si el puntero en una parte del programa es 0, puede haber otros que no están configurados en 0.

Además, la plantilla de macro/función safe_delete es muy difícil de usar correcta, porque solo hay dos lugares que se puede usar si hay un código que puede lanzar entre el nuevo y eliminar para el puntero dado.

1) Dentro de un bloque catch (...) que vuelve a lanzar la excepción y también se duplica al lado del bloque catch (...) para la ruta que no arroja. (También se duplica al lado de cada corte, retorno, continuación, etc. que puede permitir que el puntero se salga del alcance)

2) Dentro de un destructor para un objeto que posee el puntero (a menos que no haya código entre el nuevo y eliminar eso puede arrojar).

Incluso si no hay un código que pueda arrojarse al escribir el código, esto podría cambiar en el futuro (basta con que alguien venga y agregue otro nuevo después del primero). Es mejor escribir el código de una manera que se mantenga correcta incluso frente a excepciones.

La opción 1 crea tanta duplicación de código y es tan fácil equivocarse que dudo siquiera llamarlo una opción.

La opción 2 hace que safe_delete sea redundante, ya que el ptr_ que está configurando a 0 saldrá de alcance en la siguiente línea.

En resumen, no use safe_delete ya que no es seguro en absoluto (es muy difícil de usar correctamente y conduce a código redundante incluso cuando su uso es correcto). Use SBRM y punteros inteligentes.

+0

Si usa safeDelete para administrar punteros de miembros de una clase, los miembros están bien encapsulados, la hipótesis de tener más puntero a los mismos datos falla. Los datos que desea obtener solo pueden ser recuperados por el objeto, y gracias a la eliminación segura de cualquier uso del objeto contenedor después de su eliminación podría ser fácilmente detectable. El uso de safe_delete en el puntero local, o en solo uno de los punteros a los datos eliminados no tiene ningún significado. –

Cuestiones relacionadas