2010-10-31 15 views
18

Tengo un vector que relleno con punteros a los objetos. Estoy tratando de aprender una buena administración de memoria, y tengo algunas preguntas generales:¿Qué debo hacer antes de eliminar elementos en un vector de punteros a objetos asignados dinámicamente?

  1. ¿Es verdad que cuando termine con el vector, debo recorrerlo y llamar eliminar en cada puntero?
  2. ¿Por qué no tengo que llamar eliminar en el vector o cualquier otra variable que declaro sin la nueva instrucción, pero se debe invocar a borrar en los punteros?
  3. ¿Maneja C++ liberando la memoria de los punteros si el vector se declara en una función que retorna (haciendo que el vector salga del alcance)?

Respuesta

21
  1. vectores se implementan utilizando asignadores de memoria plantilla que se ocupan de la gestión de memoria para usted, por lo que son un tanto especial. Pero como regla general, no tiene que llamar al delete en variables que no se declaran con la palabra clave new debido a la diferencia entre la asignación de la pila y el montón. Si las cosas se asignan en el montón, se deben eliminar (liberar) para evitar pérdidas de memoria.
  2. No. Tiene que llamar explícitamente al delete myVec[index] mientras itera sobre todos los elementos.

Ex:

for(int i = 0; i < myVec.size(); ++i) 
    delete myVec[i]; 

Dicho esto, si usted está pensando en almacenar punteros en un vector, recomiendo el uso de boost::ptr_vector la que se encarga automáticamente de la eliminación.

+1

3: C++ liberará, por supuesto, la memoria utilizada por los punteros, ya que están asignados en la pila. Pero los objetos apuntados por esos punteros probablemente se asignen en el montón y, por lo tanto, deberán borrarse. Y, por supuesto, los punteros en el vector podrían apuntar a la pila de objetos asignados, que no se pueden eliminar. En general, nunca debe almacenar punteros no const para apilar objetos asignados en un vector. – smerlin

+1

Gracias! Eso fue muy claro! –

2

También puede usar std :: unique_ptr si tiene acceso a C++ 0x. Reemplaza el std :: auto_ptr en desuso que no se podía usar en los contenedores.

2

Todo lo que asigna con new tiene que delete más adelante. Los objetos que no se asignan explícitamente con new no deberían delete.

Si no desea administrar los objetos manualmente pero desea que el vector los "posea", puede ser mejor almacenar los objetos por valor en lugar de almacenarlos en ellos. Entonces, en lugar de std::vector<SomeClass*>, puede usar std::vector<SomeClass>.

10

¿Es cierto que cuando termine con el vector debo recorrerlo y llamar eliminar en cada puntero?

Bueno, usted no tiene que bucle a mano, también puede utilizar un algoritmo:

#include <vector> 
#include <algorithm> 
#include <memory> 

int main() 
{ 
    std::vector<Base*> vec; 
    vec.push_back(new Derived()); 
    vec.push_back(new Derived()); 
    vec.push_back(new Derived()); 

    // ... 

    std::for_each(vec.begin(), vec.end(), std::default_delete<Base>()); 
} 

Si usted no tiene un compilador de C++ 0x, puede utilizar impulso:

#include <boost/lambda/lambda.hpp> 
#include <boost/lambda/construct.hpp> 

std::for_each(vec.begin(), vec.end(), boost::lambda::delete_ptr()); 

O puede escribir su propio funtor:

struct delete_ptr 
{ 
    template <class T> 
    void operator()(T* p) 
    { 
     delete p; 
    } 
}; 

std::for_each(vec.begin(), vec.end(), delete_ptr()); 
2

Como alternativa a boost::ptr_vector como se ha mencionado por David Titarenco, puede modificar fácilmente std :: vector a la memoria de forma automática libre para que contiene indicaciones sobre la eliminación:

template<class T> 
class Group : public std::vector<T> 
{ 
public: 
    virtual ~Group() {}; 
}; 

template<class T> 
class Group<T *> : public std::vector<T *> 
{ 
public: 
    virtual ~Group() 
    { 
     std::vector<T *>::reverse_iterator it; 
     for (it = this->rbegin(); it != this->rend(); ++it) 
      delete *it; 
    } 
}; 

Toda la funcionalidad proporcionada por std :: vector se hereda por lo que agregaría artículos de la misma manera :

Group<Foo *> *bar = new Group<Foo *>(); 
bar->push_back(new Foo()); 
bar->push_back(new DerivedFoo()); 

// Deleting the Group will free all memory allocated by contained pointers 
delete bar; 
Cuestiones relacionadas