[C con Clase] [C con clase] ¿exit() libera memoria dinámica?

Steven Davidson srd4121 en njit.edu
Jue Jul 30 21:26:51 CEST 2009


Hola David,

David Inocente Romero Escalona wrote:
> Utilizo el operador predefinido "new" de C++.
> 
> Pero mi objetivo al usar la función "exit()" no es liberar memoria,
> sino terminar el programa.
> 
> En concreto, se trata de una aplicación gráfica OpenGL que utiliza el
> toolkit GLUT. Con dicho toolkit, el programa nunca termina (pues hay
> un bucle principal infinito que se encarga de ir capturando y
> manejando diversos eventos). Entonces, para poder finalizar el
> programa, no queda más remedio que usar la función "exit()" para
> matar al proceso. En dicha aplicación creo objetos 3D que pertenecen
> a clases C++ que reservar memoria dinámicamente cuando crean el
> objeto (para almacenar los vértices y los vectores normales del
> objeto OpenGL). Esas clases tiene el destructor definido e
> implementado correctamente para liberar la memoria dinámica que se
> haya podido reservar. Sin embargo, nunca elimino dichos objetos
> porque siempre tienen que estar vivos mientras la aplicación se está
> ejecutando. Mi pregunta viene de aquí. ¿al llamar a la función
> "exit()" se liberará esa memoria reservada dinámicamente (aunque no
> haya eliminado explícitamente a dicho objetos)?
> 

Si has instanciado esos objetos dinámicamente, entonces debes liberar la 
memoria dinámica explícitamente. Por ejemplo,

int main()
{
   ListaObjetos3D *pLista;
   ...
   pLista = new ListaOjbetos3D;
   ...
   glutMainLoop();

   return 0;  // Nunca llegaremos
}

Esto es un grave problema, porque no se liberará la memoria que creaste 
para el objeto. Ciertamente, los sistemas operativos modernos y en 
particular los que sean multitareas y multi-procesos eliminan toda la 
memoria perteneciente a un proceso cuando éste termina. Como se ha 
dicho, la memoria compartida con otros procesos no se eliminará, al 
menos que ya no sea compartida. Sin embargo, todo esto es cuestión del 
sistema operativo y no tiene relación alguna con el lenguaje de C++ ni 
con sus bibliotecas estándares.

> La única posible solución que se me ocurre es utilizar la función 
> "atexit()" para registrar funciones que se encarguen de eliminar
> dichos objetos antes de que finalmente se mate al proceso. Pero, ¿es
> esto necesario?
> 

La solución a este problema implica liberar la memoria antes de terminar 
el programa. Podríamos registrar una función con 'atexit()' que realice 
tal limpieza de memoria. Ahora bien, esto implicaría que tales punteros 
son globales. Por ejemplo,

ListaObjetos3D *pLista;
...
void liberar()
{
   delete pLista;  // o 'delete[]' si se trata de un array dinámico
}

int main()
{
   atexit( liberar );
   pLista = new ListaOjbetos3D;
   ...
   glutMainLoop();

   return 0;  // Nunca llegaremos
}

Claro que es posible que tengamos que hacer lo mismo para una 
terminación anormal. Podemos registrar la misma función para la señal de 
aborto. Por ejemplo,

int main()
{
   atexit( liberar );
   signal( SIGABRT, liberar );
   ...
}

En tu caso, al usar GLUT, podrías liberar la memoria en un tiempo 
determinado o debido a algún evento activado por el usuario a través de 
un periférico, como es el teclado o el ratón.


La otra solución es simplemente no tener ninguna memoria creada 
explícitamente, sino a través de algún objeto. Por ejemplo,

struct Entorno
{
   ListaObjetos3D *pLista;

   Entorno() : pLista(0)  { pLista = new ListaObjetos3D; }
   ~Entorno()  { delete pLista; }
};

Entorno entorno;
...
int main()
{
   ...
}

Así no tendremos problemas de pérdida de memoria, porque el destructor 
se llamará automáticamente al salir del programa.


Espero haber aclarado la duda.

Steven




Más información sobre la lista de distribución Cconclase