Autor
|
Tema: [C++][Consulta] Error inesperado con destructor (Leído 2,750 veces)
|
class_OpenGL
Desconectado
Mensajes: 437
Si usas Direct3D, no eres mi amigo :P
|
Hola, muy buenas. Estoy realizando un árbol binario en C++. Lo estoy encapsulando en una clase. Como cualquier árbol binario, este tiene un dato, un puntero a la izquierda y otro a la derecha. El problema es que al llamar al destructor (el cual lo elimina), el programa finaliza brúscamente. El constructor es el siguiente: template <typename T> class ArbolBinario { private: T dato; ArbolBinario *izda; ArbolBinario *dcha; void Eliminar(ArbolBinario *rama) { if(NULL != rama->izda) Eliminar(rama->izda); if(NULL != rama->dcha) Eliminar(rama->dcha); delete rama; } public: [...] ~ArbolBinario() { EliminarRamaIzda(); EliminarRamaDcha(); } [...] void EliminarRamaIzda() { if(NULL != izda) { Eliminar(izda); izda = NULL; } } void EliminarRamaDcha() { if(NULL != dcha) { Eliminar(dcha); dcha = NULL; } } [...] };
Este es la función main: int main() { ArbolBinario<int> arbol; arbol.SetDato(7, ""); arbol.ReemplazarRamaIzda(20, ""); arbol.ReemplazarRamaIzda(5, "0"); arbol.ReemplazarRamaDcha(7, "00"); arbol.ReemplazarRamaDcha(4, "0"); arbol.ReemplazarRamaIzda(1, "01"); arbol.ReemplazarRamaDcha(2, "01"); arbol.ReemplazarRamaDcha(8, ""); arbol.ReemplazarRamaIzda(10, "1"); cout << arbol.ToString(); return 0; }
Cuando uso el depurador, pongo un punto de ruptura en el destructor, y obtengo lo siguiente: Breakpoint 1, ArbolBinario<int>::~ArbolBinario (this=0x28fddc, __in_chrg=<optimized out>) at main.cpp:84 84 EliminarRamaIzda(); (gdb) continue Continuing.
Breakpoint 1, ArbolBinario<int>::~ArbolBinario (this=0x720fb0, __in_chrg=<optimized out>) at main.cpp:84 84 EliminarRamaIzda(); (gdb) continue Continuing.
Breakpoint 1, ArbolBinario<int>::~ArbolBinario (this=0x7212f0, __in_chrg=<optimized out>) at main.cpp:84 84 EliminarRamaIzda(); (gdb) continue Continuing.
Program received signal SIGSEGV, Segmentation fault. 0x004099bb in ArbolBinario<int>::Eliminar (this=0x0, arbol=0x726f58) at main.cpp:13 13 void Eliminar(ArbolBinario *arbol) { Lo que no sé es: ¿por qué se llama 3 veces al constructor? En la última llamada, ¿por qué el puntero this vale 0 (supongo que por esto el programa crashea)? Muchas gracias
|
|
|
En línea
|
| Programador aficionado. Me quiero centrar en programar videojuegos. La API que uso para crearlos es OpenGL |
|
|
|
|
MAFUS
Desconectado
Mensajes: 1.603
|
A mi entender duplicas las cosas. En el destructor vas a borrar las dos ramas por separado pero estas funciones terminan apoyándose en Eliminar, que de igual forma vuelve a borrar a la izquierda y a la derecha por sí misma. Tal vez debería ser al revés, que Eliminar estuviera a un nivel superior y fuera las que llamara a eliminar izquierda y derecha para borrar así el nodo completo.
De igual forma, tal y como lo tienes, solo EliminarRamaIzda y EliminarRamaDcha se encargan de llevar a NULL el puntero pero Eliminar no lo hace. ¿Llega el programa a un punto en que Eliminar pasará sobre un puntero que ya ha sido borrado previamente?
|
|
|
En línea
|
|
|
|
class_OpenGL
Desconectado
Mensajes: 437
Si usas Direct3D, no eres mi amigo :P
|
No entiendo muy bien eso de duplico. A ver, tengo el método Eliminar, que te elimina una rama del árbol. Este no comprueba que el árbol que le pases sea nulo (es una precondición que no será así, por así decirlo). Una vez que tengo ese método, creo otros dos que te eliminan la rama izquierda y la rama derecha, las cuales comprueban si la rama es válida (si esta no es nula). Una vez que tengo dos métodos que te eliminan dos ramas (sé que se podría haber resumido en una, pero me pareció útil para mis propósitos) tener métodos que te eliminen ramas independientes. El caso es que el constructor elimina el árbol formado por la rama izquierda y elimina el formado por la de la derecha: Destructor: Elimina rama izquierda. Elimina rama derecha No entiendo dónde está el conflicto. ________________________________________________________ He probado, desde el main, hacer lo del constructor, lo he eliminado y así si que funciona. Nuevo main: int main() { ArbolBinario<int> arbol; arbol.SetDato(7, ""); arbol.ReemplazarRamaIzda(20, ""); arbol.ReemplazarRamaIzda(5, "0"); arbol.ReemplazarRamaDcha(7, "00"); arbol.ReemplazarRamaDcha(4, "0"); arbol.ReemplazarRamaIzda(1, "01"); arbol.ReemplazarRamaDcha(2, "01"); arbol.ReemplazarRamaDcha(8, ""); arbol.ReemplazarRamaIzda(10, "1"); cout << arbol.ToString(); arbol.EliminarRamaIzda(); arbol.EliminarRamaDcha(); return 0; }
Por lo que alguna condición/requisito especial tiene que tener el destructor. _____________________________________________________________ He probado a poner cout << "Algo" << endl en el destructor y esto sale: Algo Algo Algo Algo Algo Algo Algo Algo Algo ¿Por qué se llama tantas veces? ______________________________________________________________ Soy nuevo en C++ (vengo de C), ¿delete Objeto llama al destructor del objeto?
|
|
« Última modificación: 3 Febrero 2017, 09:24 am por class_OpenGL »
|
En línea
|
| Programador aficionado. Me quiero centrar en programar videojuegos. La API que uso para crearlos es OpenGL |
|
|
|
|
MAFUS
Desconectado
Mensajes: 1.603
|
Si pudieras pasar tu código entero para probar mejor. La idea es: static void Eliminar(ArbolBinario **raiz) { // como no soy de C++ no sé si aquí el operador & // en el argumento ArbonBinario &rama te podría funcionar if(*raiz) { delete *raiz; *raiz = NULL; } } void EliminarRamaIzda() { if(!izda) { delete izda; izda = NULL; } } void EliminarRamaDcha() { if(!dcha) { delete dcha; dcha = NULL; } } ~ArbolBinario() { EliminarRamaIzda(); EliminarRamaDcha(); }
Lo dicho, si tuviera el código completo del árbol podría probarlo, pero por ahora esa es mi idea. Puede tener una infinidad de bugs, código no probado.
|
|
« Última modificación: 3 Febrero 2017, 14:30 pm por MAFUS »
|
En línea
|
|
|
|
ivancea96
Desconectado
Mensajes: 3.412
ASMático
|
void Eliminar(ArbolBinario *rama) { if(NULL != rama->izda) Eliminar(rama->izda); if(NULL != rama->dcha) Eliminar(rama->dcha); delete rama; }
Eliminar no establece las ramas a NULL. COn esta función recursiva, estás eliminando todas las ramas, pero de manera incorrecta: Primero, liberas la memoria de cada lado de la rama. Luego, llamas al destructor de la rama y la liberas. El destructor de la rama, ya llama a Eliminar. Solo que ahora, llama a Eliminar sobre unas ramas que no apuntan a nada válido.
|
|
|
En línea
|
|
|
|
class_OpenGL
Desconectado
Mensajes: 437
Si usas Direct3D, no eres mi amigo :P
|
Sii con el gdb (y mucho esfuerzo, por fin me entere del problema. Con C++ hay que tener un cuidado especial, tanto o mas que con C xD (supongo que sera cuestion de muucha practica, como siempre)
Muchas gracias por sus respuestas!!
|
|
|
En línea
|
| Programador aficionado. Me quiero centrar en programar videojuegos. La API que uso para crearlos es OpenGL |
|
|
|
|
|
Mensajes similares |
|
Asunto |
Iniciado por |
Respuestas |
Vistas |
Último mensaje |
|
|
Error inesperado en win98
Programación Visual Basic
|
BartolomeoJS
|
2
|
1,732
|
26 Agosto 2006, 00:24 am
por Ironhorse
|
|
|
GTA4 De nuestro amigo del FOro y un error inesperado de arranque!!(solucionado)
Juegos y Consolas
|
XXXXXX
|
7
|
4,240
|
26 Diciembre 2008, 03:40 am
por Embusterillo de bolsillo
|
|
|
Visual Studio C++, error destructor de clase
Programación C/C++
|
Namida
|
8
|
10,419
|
1 Mayo 2010, 16:38 pm
por Eternal Idol
|
|
|
Destructor se ejecuta bien pero da error al final de la ejecución [SOLUCIONADO]
Programación C/C++
|
SARGE553413
|
5
|
3,429
|
25 Abril 2013, 16:00 pm
por SARGE553413
|
|
|
Error inesperado en un codigo de C
Programación C/C++
|
ferchundo9
|
3
|
2,325
|
20 Junio 2017, 02:01 am
por engel lex
|
|