2010-01-20 5 views
17

Dadas dos clases solo tienen tipo de datos primitivos y ningún destructor/desasignador personalizado. ¿La especificación C++ garantiza que desasignará con el tamaño correcto?¿Usar borrar con un puntero de clase base provocará una pérdida de memoria?

struct A { int foo; }; 
struct B: public A { int bar[100000]; }; 
A *a = (A*)new B; 
delete a; 

quiero saber qué tengo que escribir un vacío virtual dtor?

He intentado g ++ y vC++ 2008 y no provocarán una fuga. Pero me gustaría saber qué es correcto en C++ estándar.

+1

Tuve un error muy grave en mi vida cuando mezclé la herencia sin métodos virtuales con el grupo de memoria. Simplemente no hagas eso, no es seguro. – vava

Respuesta

23

A menos que el destructor de la clase base sea virtual, es un comportamiento indefinido. Consulte 5.3.5/4:

Si el tipo estático del operando [del operador de eliminación] es diferente de su tipo dinámico, el tipo estático será una clase base del tipo dinámico del operando y el tipo estático tendrá un destructor virtual o el comportamiento no está definido.

+0

que se encuentra en [n3242] (http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2011/n3242.pdf) en 5.3.5/** 3 **. Ninguna de las respuestas explica lo que sucede si tienes un destructor virtual. ¿Estamos solo preocupados por el destructor aquí? Destructor a un lado, ¿la subclase real será "eliminada" de la memoria? Si es así, entonces las subclases que no necesitan destructores no tendrán fugas. –

+1

@Nathan: si la clase base tiene un destructor virtual, todo funciona. De lo contrario, el comportamiento no está definido. Cuando hay un destructor virtual, se invocan todos los destructores (cada clase derivada de la cadena tiene un destructor virtual, incluso si no se declara virtual o no se define explícitamente) y la memoria se borra. –

16

De acuerdo con el estándar C++, lo que tiene es un comportamiento indefinido: esto puede manifestarse como una fuga, puede que no. Para que su código sea correcto, necesita un destructor virtual.

Además, no necesita ese (A *) elenco. Siempre que te encuentres usando un elenco estilo C en C++, puedes estar bastante seguro de que o es innecesario o tu código está equivocado.

0

Se desasignará con el tamaño correcto, porque el tamaño que se desasignará es una propiedad de la región de memoria de montón que se obtuvo (no hay tamaño pasado a free() -como funciones!).

Sin embargo, no se llama a d'tor. Si 'B' define un destructor o contiene miembros con un destructor no trivial, no se invocarán, lo que provocará una posible pérdida de memoria. Sin embargo, este no es el caso en su muestra de código.

+1

¿Dónde ves una "función gratuita"? Una de las razones por las que C++ utiliza un 'delete' __operator__ en lugar de una función es una implementación directa del compilador. El compilador _ sabe_ conoce 'sizeof (A)', y también sabe que A no tiene un destructor virtual, por lo que está permitido llamar 'FourBytePool :: free (void * p)' detrás de las escenas. – MSalters

1

Esto es un comportamiento indefinido, tal vez todo esté bien, tal vez todo lo que no vaya bien. O no lo haga o suministre a la clase base un destructor virtual.

En la mayoría de las implementaciones esto no se filtrará - no hay funciones de miembro asignadas en el montón en la clase, por lo que lo único que se necesita cuando se hace delete es desasignar la memoria. La memoria de desasignación usa solo la dirección del objeto, nada más, el montón hace todo el resto.

1

Para datos solo primitivos, creo que está bien. Es legítimo que no desee incurrir en el costo de una tabla v en este caso. De lo contrario, un canal virtual es definitivamente preferido.

Cuestiones relacionadas