c++ - que - puntero a puntero
¿Qué debo hacer antes de eliminar elementos en un vector de punteros a objetos asignados dinámicamente? (5)
¿Es cierto que cuando termine con el vector debo recorrerlo y hacer clic en eliminar en cada puntero?
Bueno, no tienes que hacer un bucle a mano, también puedes usar 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 no tienes un compilador de C ++ 0x, puedes usar boost:
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/construct.hpp>
std::for_each(vec.begin(), vec.end(), boost::lambda::delete_ptr());
O puedes escribir tu propio functor:
struct delete_ptr
{
template <class T>
void operator()(T* p)
{
delete p;
}
};
std::for_each(vec.begin(), vec.end(), delete_ptr());
Tengo un vector que lleno con punteros a objetos. Estoy tratando de aprender a manejar bien la memoria y tengo algunas preguntas generales:
- ¿Es cierto que cuando termine con el vector, debo recorrerlo y hacer clic en eliminar en cada puntero?
- ¿Por qué no tengo que llamar a eliminar en el vector o cualquier otra variable que declare sin la nueva declaración, pero la eliminación debe ser llamada en los punteros?
- ¿C ++ controla la liberación de la memoria de los punteros si el vector se declara en una función que devuelve (lo que hace que el vector quede fuera de alcance)?
- Sí
- Los vectores se implementan utilizando asignadores de memoria de plantilla que se encargan de la administración de la memoria por usted, por lo que son algo especiales. Pero como regla general, no tiene que llamar a
delete
variables que no están declaradas con lanew
palabra clave debido a la diferencia entre la asignación de pila y pila. Si las cosas se asignan en el montón, se deben eliminar (liberar) para evitar pérdidas de memoria. - No. Tiene que llamar explícitamente a
delete myVec[index]
mientras itera sobre todos los elementos.
Ex:
for(int i = 0; i < myVec.size(); ++i)
delete myVec[i];
Dicho esto, si planea almacenar punteros en un vector, le sugiero que utilice boost::ptr_vector
que automáticamente se encarga de la eliminación.
Como alternativa a boost::ptr_vector
como lo menciona David Titarenco, puede modificar fácilmente std :: vector para liberar automáticamente la memoria para contener punteros al eliminar:
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 elementos 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;
También puede usar std :: unique_ptr si tiene acceso a C ++ 0x. Reemplaza el std :: auto_ptr obsoleto que no se pudo usar en contenedores.
Todo lo que asignes con lo new
que tienes que delete
más adelante. Los objetos que no asigne 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 almacenar los punteros a ellos. Así que en lugar de std::vector<SomeClass*>
podría usar std::vector<SomeClass>
.