Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Dudilla con Visual C++ y memoria dinámica..

Iniciado por Neuromante, 21 de Septiembre de 2007, 01:33:07 PM

« anterior - próximo »

Neuromante

Buenas! Hará cosa de 4 días que me pasaron esta web (curiosamente por un par de viñetas de humor) y me he decidido a registrarme, que parece que por aqui hay mucha gente que de esto sabe.

Bueno, estoy estudiando la técnica de sistemas de informática, y después de sacarme la "asignatura-anual-de-programación-en-c++", A.K.A. la cometiempo, me he decidido a aprender a programar de verdad xD.

El caso es que en la asignatura esta horrible usábamos el Borland C++ Builder 5. Éste tenía una chorradita muy mona para vigilar que no hicieras el cafre con los news y deletes (el codeguard). Bastante útil para tomar contacto, la verdad.
El caso es que estoy empezando a hacer un proyectillo chorra por mi cuenta y pasaba de usar el borland por temas legales -ya que voy a programar, pues al menos lo hago con licencia- y me bajé el Visual C++ Express de Microsoft, que es como que gratis. Me hice una pila usando memoria dinámica (Si, se que están ya hechas, pero por aprender más que nada) y cual fue mi sorpresa al ver que hacer un new sin un delete después no llevaba a error (pero si hacer dos deletes sobre la misma variable).
Entonces, el caso es que no se si Visual borra los objetos creados dinámicamente de manera automática al final del programa, que no te avisa o qué, aparte que he buscado alguna opción que sonara como el codeguard y no he encontrado nada por ningún lado (me han comentado que hay plugins que añaden una opción similar, pero no se ni por donde empezar, la verdad :?)

La pregunta-resúmen de toda esta parrafada es cortital: ¿Existe algún equivalente al CodeGuard -que no sea "tener cuidado" xD- en el visual C++ o mejor me cambio de API?

Gracias adelantadas, y un saludo!

Tei

Cita de: "Neuromante"Buenas! Hará cosa de 4 días que me pasaron esta web (curiosamente por un par de viñetas de humor) y me he decidido a registrarme, que parece que por aqui hay mucha gente que de esto sabe.

Bueno, estoy estudiando la técnica de sistemas de informática, y después de sacarme la "asignatura-anual-de-programación-en-c++", A.K.A. la cometiempo, me he decidido a aprender a programar de verdad xD.



El caso es que en la asignatura esta horrible usábamos el Borland C++ Builder 5. Éste tenía una chorradita muy mona para vigilar que no hicieras el cafre con los news y deletes (el codeguard). Bastante útil para tomar contacto, la verdad.

Interesante. Debe ser alguna especie de leak detector con gui en runtime, y tal.

Citar
El caso es que estoy empezando a hacer un proyectillo chorra por mi cuenta y pasaba de usar el borland por temas legales -ya que voy a programar, pues al menos lo hago con licencia- y me bajé el Visual C++ Express de Microsoft, que es como que gratis. Me hice una pila usando memoria dinámica (Si, se que están ya hechas, pero por aprender más que nada) y cual fue mi sorpresa al ver que hacer un new sin un delete después no llevaba a error (pero si hacer dos deletes sobre la misma variable).

C++ hereda la filosofia de C de ser "una forma amena y rapida de escribir ensamblador". El ensamblador que estas generando no tiene ningun codigo automagico (esto es menos verdad con C++, pero vamos a obviarlo).  Por tanto te tiene que permitir hacer las cosas mal, por si en otro contexto eso que parece esta mal, es justamente lo que en realidad querias hacer. ( Otros lenguajes no te dejan hacer mal ciertas cosas, por lo tanto hacer ciertas cosas que puedes necesitar resultan imposibles)

C++ no tiene recolector de basura. Puedes hacer new's en un bucle for, y luego salir, sin tener ningun delete. Y ningun recolector de basura hara su trabajo ahi. Simplemente se estara reservando memoria que no sera devuelta nunca dentro de la vida del programa (y por tanto desperdiciandose dentro de la vida del programa).

En principio no hay nada malo en hacer muchos new's, se supone que en algun sitio vas a recordar los punteros a las areas de memoria creadas, y te vas a acordar de hacer un delete por cada new. Es tu responsabilidad, no hay red salvavidas, pero tampoco hay techo limitante.

Siendo C++, tienes la programacion a objetos para preocuparte por estas cosas. La forma sencilla es encapsular estos problemas dentro de objetos. Aunque fuera un codigo farragoso, te la sudaria porque se preocuparia de ello el objeto.  Algo asi se hace con el objeto string en borland, imagino.

La solucion general orientada a objetos, es que el destructor del objeto sea el gemelo malvado del constructor del objeto. Todo lo que el constructor cree, lo destruya el destructor. Esto lo puede hacer un chimpance pues puede ser tan sencillo como ojinamente haya tantos deletes como news.  Pero ademas tienes que preocuparte de todos los new's creados en runtime para ese objeto. Etc.   Como antes, una vez que has encapsulado la gestion de memoria dentro del objeto, la puedes ignorar.

Yo afirmo que los objetos pueden permitirte ignorar en gran grado las cuestiones de memoria dinamica. En parte, por ejemplo, porque cuando instancias un objeto automagicamente se llama el constructor (no te preocupas de los new's pequeños) y cuando se sale del ambito, se llama al destructor.  En la practica posiblemente tengas arrays de objetos, y no podras depender solo del ambito para que se llamen a los destructores.

De todos modos hace bastantes años que no escribo nada en C++, asi que no me hagas mucho caso.


Citar
Entonces, el caso es que no se si Visual borra los objetos creados dinámicamente de manera automática al final del programa, ...

Podria tener ahi algo de automagismo. Seria un poco redundante porque si yo construyera un sistema operativo, haria que todos los punteros de memoria que le he dado a un programa. Me los apuntos, y al salir el programa, me aseguro que cada uno de ellos ha sido liberado, y sino, lo libero yo.  Todo el mundo que escribe sistemas operativos sabe que la gente que escribe compiladores son unos chapuceros y que no hay que fiarse. :D
En la practica, pues no se, quizas haya consideraciones de memoria compartida entre procesos o historias, y los sistemas operativos no hacen esto. Yo solo me puedo guiar por como construiria yo un sistema operativo si lo construyera yo.

Lo tenga o no lo tenga. No lo uses. C++ no es un lenguaje para programar mal, dependiendo de salvaguardas para novatos. Encima coger malas costumbres, que si intentas llevar tu programa a otro compilador, peten.



Citar
que no te avisa o qué, aparte que he buscado alguna opción que sonara como el codeguard y no he encontrado nada por ningún lado (me han comentado que hay plugins que añaden una opción similar, pero no se ni por donde empezar, la verdad :?)

Busca por "leak detectors" y cosas asi. Google seguro que conoce alguna libreria. Al menos para C a palo seco hay. Yo usaba una llamada mss.

Si tu programa no hace nada, y cada vez come mas memoria, necesitas uno de estos :D   o podrias hacer lo mismo leyendo tu codigo y buscando el problema visualmente.  Claro que un buen leak detector te dejara claro que la memoria que no se libera es tal.

Tambien la verdad es que "nada" te impide hacer un recubrimiento sobre new y delete, que tenga como parametro un texto descriptico de la reserva de memoria. Y hacer un log, y correr un bonito for a la salida del programa que checkee que todos los new tienen su delete.
Suena como 20 lineas de codigo..

Citar
La pregunta-resúmen de toda esta parrafada es cortital: ¿Existe algún equivalente al CodeGuard -que no sea "tener cuidado" xD- en el visual C++ o mejor me cambio de API?

No se. Yo programo en PHP, no tengo problemas de estos.

DARWINIA FTW!!

yens

Hombre mejor API para cualquier cosa relacionada con c#, visual c++, y demas que los propios "Visuals" de Microsoft no vas a encontrar, de hecho se te hará grande al principio con tantas cosas que tienen, a noser que la express venga muy recortada respecto a la pro..

Marci

Cita de: "Neuromante"ya que voy a programar, pues al menos lo hago con licencia
La otra opción para programar legalmente es que te bajes la version libre de Borland y sigas usando el code guard :wink:
http://cc.codegear.com/Free.aspx?id=24724
La version comercial se sigue llamando C++ Builder y esta version libre la denominan Turbo C++ (supongo que será una especie de homenaje)

shephiroth

Hace un tiempo estube preguntando cosillas de los memory leaks y me pasaron varios enlaces......estuve probando y hubo uno que me gusto mucho. Simplemente era un .h que macreaba los NEW NEW[] DELETE DELETE[], y una funcion que se podia llamar en cualquier momento que listaba la memoria no borrada en un archivo txt.....ahora no puedo poner el nombre q lo tengo a mano, pero en cuanto pueda te lo pongo.

Si tienes mucha prisa, busca temas que empezara yo y q tengan memory leak, seguramente lo encontraras.

P.D: Aqui lo tienes http://www.stratos-ad.com/forums3/viewtopic.php?t=8163&highlight=memory+leak

Neuromante

ooook, gracias por las respuestas!
Probaré a buscar por "leak detectors" a ver si hay algo de suerte, que este fin de semana lo he dejado abandonado..

Sobre el borland gratuíto estoy pensando en comentarlo en mi facultad, por eso de que es un COÑAZO usar una versión antigua de un programa de pago simplemente porque pasan de actualizarla y no tienen pelas para pagar la nueva versión (historia real -.-)

Un saludo!

1cacalvo

Tambien puedes usar smart_pointers!!! :D

De todas formas en Visual C++, como norma un delete por cada new...

Neuromante

Coña, si que ha servido buscar "visual c++ leak detectors":

http://msdn2.microsoft.com/en-us/library/x98tx3cf(VS.80).aspx

Ahroa solo espero que esto sea lo que estoy bsucando y no haya metido la gamba ^^u, aunque a todas luces para que el propio visual c++ lo tiene de serie :P

Cita de: "1cacalvo"
De todas formas en Visual C++, como norma un delete por cada new...

Ya.. se hartaron de decírnoslo en clase, pero cuando te estás definiendo, por ejemplo, una pila con memoria dinámica (o algún tipo de clase de la que no sabes a ciencia cierta cuantos news vas a hacer) entonces es cuando los punteros empiezan a bailar danzas africanas.. (si lo sabré yo.. que diver es que una destructora no te funcione el día de entrega -.-)

Neuromante

Bueno, por si a alguien le interesa, es algo bastante lógico si sabes de que va el asunto pero no tanto si no tienes mucha experiencia:
El Leak detector de VC++ detecta perfectamente los espacios de memoria que no se han borrado en el sitio en el que llamas a la función _CrtDumpMemoryLeaks(), si lo pones al final de la función main() (como hice yo) y tienes alguna variable estática con componentes dinámicos (una pila, por ejemplo), al llegar a la llamada a _CrtDumpMemoryLeaks() se encontrará con que la destructora de la variable estática todavía no se ha ejecutado -ya que al ser estática se ejecuta al final- y te dirá que hay un leak de memoria, aunque realmente al cerrar el programa se ejecute la destructora y tal leak no exista "al final". Lo he solucionado convirtiendo la variable en dinámica y haciendo un delete de esta antes -si no borraba algo, _CrtDumpMemoryLeaks() lo detectaría ya que con el delete he llamado antes a la destructora de la variable-.

Pues eso, que a mi me ha costado algo averiguar por que pasaba esto, al menos si alguien lo lee, que se ahorre el tiempo de investigación ;)

Warchief

Visual Leak Detector usa el CRT de VS, y es más cómodo que hacerlo tú (saca dump, stack, bla).

Si no recuerdo mal, es capaz de detectar los leaks en miembros estáticos, porque el mismo se declara como global, y aunque no tiene porqué iniciarse primero, lo cierto es que lo hace. La explicación detallada:
CitarInitializing the Memory Leak Detector

We now have the beginnings of a better memory leak detector. We can monitor every allocation, and for each allocation monitored, we can obtain and record a stack trace. The only challenge that remains is to ensure that the allocation hook function is registered with the debug heap as soon as the program starts executing. This can be very simply solved by creating a global instance of a C++ class object. The constructor will run when the program is initialized. From the constructor, we can call _CrtSetAllocHook to register our allocation hook function. But wait, what if the program we are debugging already has other global C++ class objects that allocate memory? How can we ensure that our constructor will be called first, and that our allocation hook function will be installed before any other global objects are constructed? Unfortunately, the C++ specification does not spell out any rules for deciding in which order to construct global objects. So there are no absolute guarantees that our constructor will be called first. But we can come very close to guaranteeing it. We can leverage a compiler-specific preprocessor directive that explicitly tells the compiler to ensure that our global variable is constructed as soon as possible: #pragma init_seg (compiler). This directive tells the compiler to place our global object in the "compiler" initialization segment. Objects in this segment are the first to be constructed. Next, objects in the "library" segment are constructed, and objects in the "user" segment are constructed last. The "user" segment is the default segment for global objects. Generally speaking, no normal user objects should ever be placed in the "compiler" segment, so this provides a reasonable amount of certainty that our global object will be constructed before any user objects.

Y para usarlo basta con hacer:

#ifdef _DEBUG
   #include "vld.h"
   #pragma comment(lib, "vld.lib")
#endif


Con el zip de descarga viene una página web con una explicación muy buena sobre cómo usarlo.






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.