Foros - Stratos

Programadores => General Programadores => Mensaje iniciado por: DraKKaR en 09 de Enero de 2004, 11:38:43 AM

Título: Std::vector Y Punteros
Publicado por: DraKKaR en 09 de Enero de 2004, 11:38:43 AM
 Estoy usando la std::vector para almacenar un vector de punteros a un objeto:

std::vector vector_mallas;

El problema es que usando el devpartner me ha detectado muchos errores del tipo: Dangling Pointer (es decir, se intenta acceder a una posición de memoria que ya ha sido liberada) usando la std::vector con punteros.  He estado inspeccionando el código fuente de la std::vector y sí que parece que libere memoria de sus componentes como le conviene.

La pregunta es: ¿Es bueno hacer un std::vector de punteros a algo?
Título: Std::vector Y Punteros
Publicado por: MChiz en 09 de Enero de 2004, 12:46:50 PM
 Yo lo he hecho mil veces y no hay ningun tipo de problema.
Título: Std::vector Y Punteros
Publicado por: CoLSoN2 en 09 de Enero de 2004, 01:09:14 PM
 secundo (con s) a MChiz
Título: Std::vector Y Punteros
Publicado por: Zaelsius en 09 de Enero de 2004, 02:01:55 PM
 Tanto DevPartner como Purify se equivocan siempre con la STL , así que don't worry.  ;)

Para que te quedes más tranquilo copio unas lineas de la FAQ de la SGI STL(igualmente aplicable a cualquier implementación de STL):

Citar
Why am I getting uninitialized memory reads from PurifyTM?
We believe that the uninitialized memory read (UMR) messages in STL data structures are artifacts and can be ignored.

Why does Bounds CheckerTM say that I have memory leaks?
This is not an STL bug. It is an artifact of certain kinds of leak detectors.

Bounds Checker es el antiguo nombre del componente de detección de errores de DevPartner.
Título: Std::vector Y Punteros
Publicado por: DraKKaR en 09 de Enero de 2004, 02:45:23 PM
 Vale, me quedo más tranquilo.

Gracias, ya me estaba rallando con esos errores.
Por cierto, ya que estamos... ¿Como haceis vosotros para pillar esos fallos extraños de ejecución que no tiene una explicación aparente?
Título: Std::vector Y Punteros
Publicado por: Zaelsius en 09 de Enero de 2004, 02:52:33 PM
 ¿A qué fallos te refieres? En Visual C++, pues modo debug, F5, y 'palante'  
Título: Std::vector Y Punteros
Publicado por: DraKKaR en 09 de Enero de 2004, 09:47:05 PM
 El problema lo tengo con un delete sobre un puntero a una clase de mi motor reservado con new.
Al hacer el delete me da un error de:

User breakpoint called from code at 0x77f65a58

en el stack de llamadas veo que al ahcer el delete la ejecución se ha metido por el fichero dbgheap.c llamando a la función _free_dbg(void*,int). El error lo ha dado en la siguiente linea de esa función:

       /*
        * If this ASSERT fails, a bad pointer has been passed in. It may be
        * totally bogus, or it may have been allocated from another heap.
        * The pointer MUST come from the 'local' heap.
        */
       _ASSERTE(_CrtIsValidHeapPointer(pUserData));

¿Alguna idea de que peude pasar?
Título: Std::vector Y Punteros
Publicado por: Zaelsius en 09 de Enero de 2004, 10:51:49 PM
 Pues mirando eso que has puesto, sólo se me ocurre que el new y el delete se hagan desde módulos diferentes, tal vez desde aplicación/dll  :huh:  y que teniendo zonas de memoria distintas sea esa la causa del error al hacer delete.
Título: Std::vector Y Punteros
Publicado por: ethernet en 09 de Enero de 2004, 11:24:16 PM
 Mucho cuidado con los punteros. Posiblemente estes intentando hacer un delete sobre un puntero que ya ha sido liberado. Para evitar estas mierdas lo mejor es usar ref count.

saludos
Título: Std::vector Y Punteros
Publicado por: Kriller en 10 de Enero de 2004, 02:07:19 AM
 Otra forma de evitar hacer un delete de un puntero ya liberado es poniendo siempre el puntero a NULL justo después de hacer el delete (con una macro por ejemplo). El delete no hace nada cuando se le pasa NULL así que el segundo delete no tendría ningún efecto.

Personalmente esto me gusta más que el contador de referencias.
Título: Std::vector Y Punteros
Publicado por: ethernet en 10 de Enero de 2004, 11:07:39 AM
 A mi eso me parece bastante mas cutre, mas q nada porque no sirve para nada en este caso (*) y lo q es mas importante y para lo q sirve tener ref count: Hasta que todas las referencias  a esa instancia no hayan desaparecido no se libera el objeto. Con esa macro lo unico que haces es evitar petes extraños.  No son comparables

(*)

int *p,*o=new int;
p=o;
delete o; o = 0;
*p=1000; // petada;

Título: Std::vector Y Punteros
Publicado por: Kriller en 10 de Enero de 2004, 11:43:59 AM
 Eso es verdad, no son comparables. Ahora bien, que lo de poner un puntero a NULL después de liberarlo es cutre no estoy en absoluto de acuerdo, es todo lo contrario. De esa manera siempre sabes con total certeza que si un puntero es distinto de NULL, entonces apunta a algo válido.

Lo del contador de referencias creo que no es necesario en la mayoría de los casos y que con el otro método es completamente suficiente (vamos, a mí me va muy bien). Eso sí, te obliga a ser muy disciplinado y riguroso con cuándo y dónde reservas/liberas pero, ¿no hay que serlo también con el resto?  :P

Saludos.
Título: Std::vector Y Punteros
Publicado por: DraKKaR en 10 de Enero de 2004, 11:55:38 AM
 Gracias a todos por responder.

ZaelsiuS: El new y el delete los hago desde el mismo módulo, solo que en funciones distintas.

ethernet: Me gusta eso del ref count, pero como implementarlo? ¿sobrecargando el operator= para los punterios?  :blink:

Además hay un par de cosas que no os he dicho:
- Este fallo solo me pasa en modo Debug (lógico ya que el error me lo da dentro de un ASSERTE como os he copiado arriba), en modo Release no me da ningún problema (como odio cuando en release va bien y en debug no y viceversa v.v)

- Antes de hacer el delete observo el contenido del puntero en el watch view y no parece un sector corrupto, todos sus datos son perfectamente válidos.
Título: Std::vector Y Punteros
Publicado por: ethernet en 10 de Enero de 2004, 01:58:53 PM
 drakar -> mira la clase smart_ptr

Kriller->

has visto el ejemplo q te he puesto?

En ese ejemplo se ve q por mucho NULL q pongas la aplicacion petara igual, sin embargo con ref count no petara.  Y es que hay algun problema para el progrmador cuando solo tenems un puntero a la zona de memoria? el problema viene cuando tenemos varios y en ese caso la macro esa no sirve para absolutamente nada XD.

Ademas, es mucho menos cutre sobrecargar delete y delete[] que usar macros de mierda.

saludos
Título: Std::vector Y Punteros
Publicado por: seryu en 11 de Enero de 2004, 12:17:06 AM
Cita de: "ethernet"Ademas, es mucho menos cutre sobrecargar delete y delete[] que usar macros de mierda.
pobres macros, ni qe fuera mordiendo a la gente
Título: Std::vector Y Punteros
Publicado por: Kriller en 11 de Enero de 2004, 02:08:00 AM
 ethernet, sí he visto el ejemplo y por supuesto que petaría, por eso digo que hay que anderse con mucho ojo. Un caso real en el que me planteé usar contador de referencias: me planteaba para mi motor que diera la posibilidad al usuario de tener varios objetos CCamara y poder pasarle al motor una u otra en cada momento. Si el usuario se cepillaba el objeto CCamara que estuviera usando el motor y luego seguía usando el motor entonces explotaría; con un contador de referencias se evitaría ese problema. Pero al final decidí emplear otra filosofía  ;) .

Como dice seryu, las macros no muerden, aunque yo las utilizo en muy determinadas circunstancias. De hecho hay casos en los que no hay otra manera de hacer algo. Por ejemplo, para lo que yo digo: sobrecargando el delete no puedes poner a NULL el puntero que te han pasado, tendrías que hacerte una función tuya equivalente a la que le pasas un doble puntero.

A ver, no digo que no haya que usar contadores de referencias, sólo digo que la mayor parte del tiempo puedes vivir sin ello y que por eso no me gusta como filosofía permanente, sólo hay que emplearlas en casos concretos en los que realmente te reporten un beneficio.
Título: Std::vector Y Punteros
Publicado por: ethernet en 11 de Enero de 2004, 11:16:06 AM
 Umh, siempre puedes usar una referencia a un puntero en vez de puntero a puntero
Y por lo general, macros sucks mucho

saludos
Título: Std::vector Y Punteros
Publicado por: DraKKaR en 16 de Enero de 2004, 10:33:43 PM
 ¡Al fin! dios mio! he hallado el puto problema! que he encontrado de chiripa...

Resulta que tendo una DLL que contiene una clase. Entonces, si desde el módulo principal que carga la DLL intento crear una instancia a esa clase con:

MiClase *ale=new MiClase;

Pues resulta que al hacer el delete me daba el mensaje ese de assert que os comentaba al principio.
Después de micho carcomerme la cabeza.. me he dado cuenta que para crear una instancia de una clase que hay en una DLL (conclusiones propias...) debes hacerlo dentro de la propia DLL.
Ahora en la DLL hay una función
MiClase *CreaMiClase(void){ return new MiClase; }
que crea la instancia y me devuelve un puntero a ella.

Despues de hacer ese cambio.. todo perfecto y suave. Hay que ver, nunca habia leido nada sobre eso v.v.
Bueno, espero que mi experiencia os sirva como me ha servido a mí (pero sin tantos kebraderos de cabeza y intentos de suicidio).


Otra cosa, haciendo caso a ethernet estaba metiendo boost::shared_ptr<> en mi códig, y la verdad es que tiene muy buenas aplicaciones. Lo que no me gusta es que empastra mucho el código, pero eso debería ser lo de menos.
¿Alguno de vosotros la ha usado?¿Que opinión le merece al respecto?

Saludos.

Título: Std::vector Y Punteros
Publicado por: BeRSeRKeR en 16 de Enero de 2004, 11:10:54 PM
 Si el problema era que creabas la instancia en la DLL y la eliminabas en la aplicación o viceversa, entonces, ZaelSiuS ya te lo indicó unos mensajes atrás:

Cita de: "ZaelSiuS"Pues mirando eso que has puesto, sólo se me ocurre que el new y el delete se hagan desde módulos diferentes, tal vez desde aplicación/dll  :huh:  y que teniendo zonas de memoria distintas sea esa la causa del error al hacer delete.

Ahora bien, si lo que estás diciendo es que no puedes crear una instancia de una clase implementada en una DLL fuera de ella, entonces suena bastante raro. :D

Saludos.
Título: Std::vector Y Punteros
Publicado por: DraKKaR en 17 de Enero de 2004, 11:25:34 AM
 No, sí que puedo crear una instancia fuera de la DLL, lo que pasa es que cuando voy a hacer el delete el programa me petaba si el new no lo habia hecho desde la DLL. Pero el delete sí podia hacerlo desde el modulo principal.

Es decir, antes hacia el new y el delete en el mismo modulo (programa principal) y petaba. Cuando hice el new desde la DLL, ya se corrigió.