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?
Yo lo he hecho mil veces y no hay ningun tipo de problema.
secundo (con s) a MChiz
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.
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?
¿A qué fallos te refieres? En Visual C++, pues modo debug, F5, y 'palante'
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?
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.
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
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.
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;
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.
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.
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
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
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.
Umh, siempre puedes usar una referencia a un puntero en vez de puntero a puntero
Y por lo general, macros sucks mucho
saludos
¡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.
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.
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ó.