2010-09-29 16 views
16

Al leer las respuestas a this question noté que las respuestas (this por ejemplo) implican que se puede llamar a operator delete incluso cuando la sentencia delete se ejecuta en un puntero nulo.¿Por qué se invoca "operador delete" cuando llamo "eliminar" en un puntero nulo?

Así que escribí un pequeño fragmento:

class Test { 
public: 
    void* operator new(size_t) { /*doesn't matter*/ return 0; } 
    void operator delete(void* ptr) { 
     ptr; //to suppress warning and have a line to put breakpoint on 
    } 
}; 

int main() 
{ 
    Test* ptr = 0; 
    delete ptr; 
} 

y - sorprendentemente para mí - Test::operator delete() se invoca con ptr sosteniendo un puntero nulo.

Según tengo entendido, operator new asigna memoria y operator delete devuelve la memoria al asignador. Si llamo a la instrucción delete en un puntero nulo, significa que no había ningún objeto detrás del puntero y que no hay memoria para regresar al asignador.

delete declaración incluye invocar un destructor. Cuando paso un puntero nulo, el destructor seguramente no se invoca; C++ se ocupa de eso. Entonces, ¿por qué se invoca operator delete en este caso?

+0

Pregunte también por qué se invoca 'operator new' cuando asigna una matriz de longitud cero:' new Test [0]; '...;) – ybungalobill

+1

@ybungalobill: Eso es más fácil: el estándar requiere que el puntero devuelto sea válido y distinto . – sharptooth

+0

Tenga en cuenta que si convierte el destructor en virtual, no se invocará la sobrecarga 'operator delete'. Las implementaciones generalmente invocan la función directamente desde el destructor y llaman al destructor sin una comprobación de nulo (guardando algunas instrucciones). Solo cuando la llamada necesita despacho virtual es el cheque realizado por adelantado. – avakar

Respuesta

18

El idioma en el próximo estándar de C++ 0x (sección 5.3.5 [expr.delete]) es el siguiente:

Si el valor del operando de la expresión de supresión no es un valor de puntero nulo , la expresión de supresión llamará a la función de desasignación (3.7.4.2). De lo contrario, es sin especificar si se llamará a la función de desasignación . [Nota: La función de desasignación se llama independientemente de si el destructor para el objeto o algún elemento de la matriz arroja una excepción. - nota final]

Por lo tanto, es un comportamiento no especificado, algunos compiladores puede llamar operator delete cuando se elimina un puntero NULL y otros no.

EDITAR: El término función de desasignación utilizado por la norma parece estar causando cierta confusión. Viene con una referencia. Algunos lenguaje clave del 3.7.4.2 [basic.stc.dynamic.deallocation] que puede ayudar a aclarar:

Si una clase T tiene una función miembro llamada cancelación de asignación operator delete con exactamente un parámetro, que es una función (no-colocación) la función de cancelación de asignación de costumbre.

El estándar es también muy claro que operator delete necesidades definidas por el usuario para aceptar un parámetro que es un valor de puntero nulo:

El valor de la primer argumento suministrado a una función de cancelación de asignación puede ser una valor de puntero nulo; de ser así, y si la función de desasignación es una suministrada en la biblioteca estándar, la llamada no tiene efecto.

Pero debido al comportamiento no especificado 5.3.5, no debe confiar en que se llame a su operator delete cuando el puntero es nulo.

+0

Hmm, este fragmento habla de la función de desasignación, no del operador. –

+0

C++ 03 parece ser vago en el tema. Dice "si el valor del operando de eliminación es el puntero nulo, la operación no tiene efecto", entonces, "Si la expresión de eliminación llama a la función de desasignación de implementación ...", entonces, "La expresión de eliminación llamar a una función de desasignación ". Entonces, o bien no debe llamar al operador sobrecargado, o no está especificado, o debe llamarlo. Una de las tres ;-) –

+0

@Hans: función de desasignación es la función que implementa 'operator delete'. Esta terminología proviene del hecho de que los operadores aparecen en expresiones, mientras que la función que los implementa es función * are *. En otras palabras, necesitas separar de alguna manera tu terminología. – ybungalobill

10

Operator delete es como cualquier otro operador, ¿por qué no se invocará? No puede examinar sus argumentos antes de invocar al.

Esto es como preguntar por qué operator+ se invoca cuando se está añadiendo 0.

+10

La declaración 'delete' no solo llama a' operator delete', primero llama al destructor, y se realiza una comprobación nula antes de llamar al destructor (y por lo tanto antes de llamar 'operator delete'). 'operator delete' no es como otras sobrecargas del operador. –

+0

Está bien, pero no hay forma de que el compilador esté seguro de que una eliminación de operador definida por el usuario no es operativa cuando se le da un puntero nulo. Podría, por ejemplo, registrar algo que indique que intentó borrar un puntero nulo. –

+2

De acuerdo con Ben Voigt: cuando escribe 'delete p;', el compilador llama primero al destructor del objeto y luego a la función de desasignación 'operator delete'. El sistema debe poder diagnosticar que el puntero es 0 para evitar llamar al destructor (que no llamará), por lo que técnicamente también podría evitar llamar al descriptor de distribución. –

Cuestiones relacionadas