2010-09-14 58 views
5

¿Cómo puedo liberar memoria en un vector de puntero? Aquí está el código:¿Cómo puedo liberar un vector de puntero?

class A 
{ 
    private: 
     int x,y,z; 
    public: 
     A(param1, param2, param3) 
     { 
      x=param1; 
      y=param2; 
      z=param3; 
     } 
     ~A() 
     { 
      //prompts an alertbox, warning me about the successful call of the destructor; 
     } 
}; 

... 
vector<A*> list; 
list.push_back(new A(1,2,3)); 

list.erase(list.begin()+index);//SHOULD delete the object from the memory; 
list.clear(); 

descubrí que .erase() no liberar memoria, ni llama al destructor; Traté de usar delete en cada entrada de lista con una iteración, pero se bloquea después de una iteración. Ya se verificó si la entrada de la lista ya era NULL, para evitar cualquier error. ¿Me estoy perdiendo algo? Además, debo usar solo STL, no necesito Boost.

+0

Tenga en cuenta que llamar a 'borrar' en un puntero' NULL' es seguro. –

+4

Es posible que desee utilizar un 'boost :: ptr_vector' de la biblioteca Boost Ptr Container en su lugar. –

+3

¿por qué usar 'A *' cuando lo haría 'A' simple? –

Respuesta

0
 
for(size_t i = 0; i < list.size(); ++i) 
{ 
    delete list[i]; 
} 

list.clear(); 

Si hace algo como esto y su código se bloquea, publique el código exacto y la información de bloqueo.

+0

El uso de iteradores aquí será más eficiente e independiente del contenedor (es decir, más tarde puede cambiar a la lista sin soporte de acceso aleatorio). –

8

list.erase desasignará la memoria para sus elementos miembros (y llamará a sus destructores, si existen); no llamará al delete en ellos.

Un Boost shared_ptr sería la forma obvia de hacer esto. Si no desea usar eso, o bien va a escribir su propia clase de puntero inteligente, o recorrer el list y llamar al delete en cada puntero antes de llamar al erase. Esto se puede hacer perfectamente con algo como:

void my_delete(A *p) 
{ 
    delete p; 
} 

... 

std::for_each(list.begin(), list.end(), my_delete); 
+3

+1: siempre, siempre, use punteros inteligentes a menos que realmente sepa lo que está haciendo. – Puppy

+1

@DeadMG, sí, cuéntame más sobre las dependencias cíclicas con shared_ptr :-) –

+3

@Oli, shared_ptr definitivamente no es la forma obvia ya que no hay intención de compartir estos objetos. std :: unique_ptr de C++ 0x, ptr_vector de boost o, en el peor de los casos, intrusive ptr parece ser una opción más obvia. –

4
for(std::vector<A*>::iterator i = list.begin(), endI = list.end(); i != endI; ++i) 
{ 
    delete *i; 
} 
list.clear(); 

o, utilizando las nuevas funciones lambda

std::for_each(list.begin(), list.end(), [](A* element) { delete element; }); 
list.clear(); 
+0

+1 para responder a la pregunta La forma en que se pretendía responder. – rubenvb

+0

Ojalá estuviera funcionando ... me da los mismos errores que antes. – Tibor

+0

No sé dónde se puede colgar, pero estoy casi seguro de que no está en el bucle for_each. Tal vez esté accediendo a algunos de los objetos eliminados después de la destrucción, lo que provocará un bloqueo. –

3

erase sólo borra lo que está en el vector (los punteros) sin hacer nada acerca de lo que podría apuntar a.

Si desea que se elimine el punto, debe manejarlo usted mismo.

Mi consejo sería evitar el manejo cualquier de esto usted mismo, y considere usar Boost ptr_vector en su lugar.

+1

Aunque OP me pidió que no usara boost, prefiero esta respuesta. La programación en C++ sin Boost es como escalar con un brazo atado en la espalda: posible, pero estúpido. –

2

Al destruirse, un contenedor STL destruirá los objetos que contiene. Si esos objetos son punteros, destruirá los punteros. Para los indicadores desnudos, tontos, esto no eliminará los objetos que apuntan a. Es por eso que generalmente es mejor usar punteros inteligentes para eso. Los punteros inteligentes eliminarán los objetos a los que se refieren al eliminarlos; std::shared_ptr realiza un seguimiento de la copia de punteros y la cantidad de referencias a un objeto dado existente, y solo eliminará el objeto cuando muera el último puntero. Este siempre es un buen primer candidato cuando busca un puntero inteligente adecuado. Su contenedor se declararía así: std::vector< std::shared_ptr<A> >

Sin embargo, su compilador/lib estándar no puede venir con std::shared_ptr, que es una característica del siguiente estándar de C++, generalmente esperado para el próximo año. Podría, sin embargo, vienen con std::tr1::shared_ptr, que es una característica TR1 a partir de 2003. (Si todo lo demás falla, tiene impulso boost_shared_ptr, pero ya se descartó impulso.)

You pueden los objetos manualmente gestionar de forma dinámica asignados en STL contenedores, pero es una carga y propensa a errores. Por ejemplo, debe evitar que las funciones regresen antes de tiempo (antes de la limpieza manual) a través de las declaraciones o excepciones return, y debe tener cuidado con las operaciones de copia en los contenedores.(De lo contrario, dos contenedores tendrían punteros que hacen referencia a los mismos objetos, que luego podría tratar de destruir dos veces).
La gestión manual de recursos es un PITA, propenso a errores y es mejor evitarlo.

1

El código que ha publicado no es C++ legítimo. Además, el borrado no elimina los objetos que ha asignado, solo borra los contenidos del vector, que en su caso son punteros. Los objetos reales que ha asignado no se eliminan. Aquí hay una forma correcta de hacer lo que quiere:

#include <vector> 
#include <algorithm> 

class A 
{ 
    int x,y,z; 

public: 
    A (int param1, int param2, int param3) : 
     x (param1), y (param2), z (param3) 
    { 
    } 
}; 

struct Deleter 
{ 
    template <typename T> 
    void operator() (T *obj) const 
    { 
     delete obj; 
    } 
}; 

int 
main() 
{ 
    std::vector<A*> list; 

    list.push_back (new A (1, 2, 3)); 
    list.push_back (new A (4, 5, 6)); 
    list.push_back (new A (7, 8, 9)); 

    std::for_each (list.begin(), list.end(), Deleter()); 
    list.clear(); 
} 

También puede mirar en Boost Ptr Container biblioteca que soluciona este problema de una manera segura y reutilizable. En C++ 0x, existe una clase de plantilla std :: unique_ptr que admite la semántica móvil y se puede usar con contenedores STL y algoritmos para limpiar la memoria automáticamente.

Cuestiones relacionadas