reutilización reutilizacion redefinición poo miembros metodos herencia heredados destructores derivadas derivada constructores clases clase caracteristicas c++ gcc crash undefined-behavior virtual-destructor

c++ - reutilizacion - El código se bloquea cuando la clase derivada ''destructor es virtual y la clase base'' dtor no es



reutilizacion de miembros heredados (2)

Probé el siguiente código en gcc 4.4.5.

Si el miembro ''datos'' no está presente, el código se ejecuta correctamente, pero en su presencia, se bloquea. Tampoco falla cuando la clase derivada ''dtor no es virtual.

Soy consciente de que el comportamiento sería indefinido como figura en C ++ 03 (5.3.5 / 3) en ambos casos, pero aún así, ¿podría alguien darme alguna explicación de por qué falla en el último caso?

Y sí, sé que UB significa que cualquier cosa puede suceder, pero aún así me gustaría saber detalles específicos de la implementación.

#include<iostream> using std::cout; struct base{ int data; base(){ cout << "ctor of base/n"; } ~base(){ cout << "dtor of base/n"; } }; struct derived : base{ derived(){ cout << "ctor of derived/n"; } virtual ~derived(){ cout << "dtor of derived/n"; } }; int main(){ base *p = new derived; delete p; }


Suponiendo que lo que sucede en mi sistema (gcc 4.6.0, linux x86_64) es el mismo que el tuyo (también se bloquea con data y se ejecuta sin), el detalle de la implementación es que p no apunta al principio del bloque de memoria asignado para el objeto de tipo derived .

Como valgrind me dijo,

Address 0x595c048 is 8 bytes inside a block of size 16 alloc''d

Puedes verlo por ti mismo si imprimes los valores de los punteros:

derived * d = new derived; std::cout << d << ''/n''; base *p = d; std::cout << p << ''/n'';

Y la razón para eso es que el diseño del objeto en gcc es {vtable, base, derived}

Cuando base está vacía, el tamaño de {vtable, base, derived} y {base} resulta ser el mismo porque la asignación de un objeto de clase vacía ocupa un número distinto de cero de bytes, que es igual en ambos casos.

Cuando derivada no tiene funciones virtuales, vtable no está presente, las direcciones nuevamente son las mismas y la eliminación tiene éxito.


el tamaño de los dos tipos no coincide y el diseño en su ejemplo debe diferir.

está comparando tipos de pod versus un tipo con un vtable (el diseño y los desplazamientos están definidos por la implementación). cuando se llama al destructor, se supone que la dirección de implícito tiene el diseño de la base , pero esto en realidad se derived . lo que se ejecuta es equivalente a escribir / leer desde una dirección no válida.