c++ - pila - Comprobación NULA antes de eliminar un objeto con una eliminación sobrecargada
eliminar un nodo de una lista enlazada en c++ (11)
¿Es una buena idea verificar NULL antes de llamar a eliminar cualquier objeto?
¡No!
int *p = NULL;
delete p ; //no effect
La Norma dice [Sección 5.3.5 / 2]
Si el operando tiene un tipo de clase, el operando se convierte en un tipo de puntero llamando a la función de conversión mencionada anteriormente, y el operando convertido se usa en lugar del operando original por el resto de esta sección. En cualquiera de las dos alternativas, si el valor del operando de eliminación es el puntero nulo, la operación no tiene efecto .
Además en la Sección 18.4.1.1/13
void operator delete(void* ptr) throw();
void operator delete(void* ptr, const std::nothrow_t&) throw();
Comportamiento por defecto:
- Por un valor nulo de ptr, no hacer nada .
- Cualquier otro valor de ptr será un valor devuelto anteriormente por una llamada al operador predeterminado nuevo, que no fue invalidado por una llamada interpuesta al operador eliminar (void *) (17.4.3.7). Para un valor no nulo de ptr, se reclama el almacenamiento asignado por la llamada anterior al nuevo operador predeterminado.
EDITAR :
James Kanze here dice que
Sigue siendo la responsabilidad del operador eliminar (o eliminar []) para verificar; el estándar no garantiza que no se le dará un puntero nulo; el estándar requiere que sea un no-op si se le da un puntero nulo. O que la implementación tenga permiso para llamarlo. Según el último borrador, "El valor del primer argumento proporcionado a una función de desasignación puede ser un valor de puntero nulo; si es así, y si la función de desasignación es una suministrada en la biblioteca estándar, la llamada no tiene efecto". No estoy muy seguro de cuáles son las implicaciones de que "se proporciona uno en la biblioteca estándar", deben tomarse literalmente, ya que su función no es la proporcionada por la biblioteca estándar, la frase no parece aplicarse. . Pero de alguna manera, eso no tiene sentido.
Esto surgió como uno de los comentarios de revisión de código.
¿Es una buena idea verificar NULL antes de llamar a eliminar cualquier objeto?
Entiendo que eliminar las comprobaciones del operador para NULL internamente y es redundante, pero el argumento expuesto fue eliminar, ya que un operador puede estar sobrecargado y si la versión sobrecargada no comprueba el NULL, puede fallar. Entonces, ¿es seguro y razonable suponer que si y cuándo se eliminará la eliminación, se comprobará si el NULL está pendiente o no? A mi entender, es razonable asumir el primer caso en que la eliminación sobrecargada se ocupará de la comprobación NULA, y el punto de revisión no es válido. ¿Qué piensas?
¿ No es necesario comprobarlo? Si alguien sobrecarga el método, es su responsabilidad hacer lo que sea con NULL.
De los documentos estándar, 18.5.1.1.13 bajo delete
,
Comportamiento por defecto: Si ptr es nulo, no hace nada. De lo contrario, recupera el almacenamiento asignado por la llamada anterior al operador new.
Por lo tanto, no tiene que verificar por defecto ..
No es necesario comprobar si hay NULL antes de eliminar. Si alguien tiene una sobrecarga, delete
con algo que no se comporte de manera estándar, ese es el verdadero problema. Nadie debe tomar a la ligera la tarea de delete
sobrecarga y siempre debe admitir el comportamiento esperado, como verificar NULL y no realizar ninguna acción.
Sin embargo, para lo que vale la pena, siempre debe recordar asignar cero a cualquier puntero que haya eliminado, a menos que, por ejemplo, también esté a punto de eliminar el puntero:
void MyObj::reset()
{
delete impl_;
impl_ = 0; // Needed here - impl_ may be reused / referenced.
}
MyObj::~MyObj()
{
delete impl_; // No need to assign here as impl_ is going out of scope.
}
No hay necesidad de comprobar nulo. El operador delete hace chck para null, por lo que no es necesario realizar una comprobación adicional.
Un poco de pedantería de C ++: NULL no es un concepto incorporado. Sí, todos sabemos lo que significa, pero en C ++ antes de C ++ 0X, el concepto de puntero nulo es simplemente el valor 0. NULL suele ser una macro específica de la plataforma que se expande a 0.
Con C ++ 0X obtenemos nullptr que es más claro que un cero simple y no es convertible a ningún tipo integral excepto bool, y es un concepto mejor que NULL (o quizás una mejor implementación del concepto detrás de NULL).
Yo diría que es responsabilidad de un delete
sobrecargado comportarse como usted espera que el delete
comporte. Es decir, debe manejar los punteros NULL como un no-op.
Y así, cuando se llama a un borrado sobrecargado, no debe verificar NULL. Debe confiar en la eliminación sobrecargada para implementarse correctamente.
Yo diría que esa es una razón más para asegurarse de que si usted sobrecarga al operator delete
, entonces siempre debe hacer que se verifique el valor NULL
, de lo contrario está rompiendo la semántica.
Yo diría que las preguntas contienen información incompleta. Mi tienda aún tiene una comprobación de NULL antes de eliminar en nuestro estándar de codificación, ya que todavía tenemos una configuración de compilador / plataforma que debemos admitir y que entra en un comportamiento indefinido con el operador de eliminación de valores si se pasa a NULL. Si el póster original tiene una situación similar, entonces hay un punto en la comprobación de NULL, de lo contrario, ¡cambie el estándar de codificación!
delete (T*)0;
es válido y no hace nada, igualmente free(NULL);
También es válido y no hace nada. Si sobrecarga al operador de delete
, su implementación debe llevar la misma semántica. El estándar dice cómo funcionará la delete
estándar, pero no creo que diga cómo debe comportarse una delete
sobrecargada. En aras de la coherencia con el comportamiento estándar / predeterminado, debe permitir (T*)0
como entrada.
No, no compruebe si es nulo. El estándar dice que delete (T*)0;
es válida. Simplemente complicará su código sin beneficios. Si la operator delete
está sobrecargada, es mejor verificar si hay un valor nulo en la implementación del operador. Sólo guarda las líneas de código y los errores.
EDITAR: Esta respuesta fue aceptada y upvoted, sin embargo, en mi opinión, no fue muy informativo. Aquí hay una pieza faltante en todas las respuestas y, por motivos de conciencia, permítanme agregar esta última pieza aquí.
El estándar en realidad dice en [basic.stc.dynamic], al menos desde C ++ 03:
Cualquier función de asignación y / o desasignación definida en un programa de C ++, incluidas las versiones predeterminadas en la biblioteca, se ajustará a la semántica especificada en 3.7.4.1 y 3.7.4.2.
Donde las secciones a las que se hace referencia, así como algunos otros lugares en el estándar enumerado en otras respuestas, dicen que la semántica de pasar un puntero nulo es un no-op.