2010-12-18 12 views
9

Tengo un montón de código donde estoy eliminando contenedores vectoriales que tienen punteros en ellos, es decir, primero tengo que eliminar todos los punteros y luego borrar el contenedor. Cada vez iteraba y eliminaba los punteros manualmente (conozco stl :: algorithms for_each). Para eludir todo ese código, creé una plantilla para eliminar todos los contenedores vectoriales que tienen un puntero. Hasta aquí todo bien.Eliminar cualquier contenedor usando plantillas

Ahora tengo varios tipos más de contenedores, incluidos mapas, contenedores simultáneos, etc. todos con la misma funcionalidad al final en cuanto a eliminación. La función DeleteContainer(std::vector<T*>& VecIn) que tengo solo puede funcionar en vectores como se mencionó anteriormente. ¿Hay alguna manera de hacerlo lo suficientemente genérico como para trabajar en todos los contenedores?

EDIT: Gracias por todas las respuestas, me gustaría poder seleccionar más de una. A cualquiera que se tropiece con esta pregunta, lea todas las respuestas y no solo la seleccionada, ya que todas proporcionan información excelente.

Respuesta

7

Ya tiene una respuesta válida, pero sólo para proporcionar una alternativa, creo que usted debe considerar el uso Boost Pointer Container y se deja manejar la gestión de memoria:

Esta biblioteca proporciona por lo tanto containe norma similar rs que son para almacenar objetos distribuidos o clonados (o en el caso de un mapa, el objeto mapeado debe ser un objeto clonado asignado). Para cada uno de los contenedores estándar hay un contenedor contenedor equivalente que toma propiedad de los objetos de una manera segura de excepción .

3

sólo puede utilizar boost::shared_ptr<T> restaurantes en vez de T* y no será motivo de DeleteContainer. Pero si usted no quiere hacer esto, usted puede hacer algo como esto

template<class T> 
void DeleteContainer(typename T::iterator begin, typename T::iterator end) 
{ 
for(;begin!=end;++begin) 
    delete *begin; 
} 

entonces usted puede simplemente llamar a cualquier contenedor STL desea de esta manera:

std::some_container<int*> s; 
DeleteContainer<std::some_container<int*> > (s.begin(), s.end()); 
+0

Esto no es muy C++ ish. El contenedor no es una excepción segura ya que está llamando al eliminador manualmente. Debe envolver el contenedor en un objeto ab para que RAII llame a la función automáticamente cuando el contenedor se salga del alcance. –

+0

Mismo comentario que la otra respuesta, debe manejar los contenedores asociativos de forma diferente. – Nim

4

voy a mucha gente y segundo avise mediante shared_ptr o impulsar contenedores puntero. Sin embargo, puede escribir

template <typename Iter> 
void delete_pointers(Iter begin, Iter end) 
{ 
    for (; begin != end; ++begin) delete *begin; 
} 

Uso:

std::vector<Foo*> v; 

// Initialize Foo objects 

delete_pointers(v.rbegin(), v.rend()); 

utilizo rbegin y rend en lugar de begin y end porque a veces, la gente quiere que se eliminen los objetos en el orden inverso al que fueron creados.

También puede hacer

void destroyFoo(Foo* x) { delete x; } 

std::for_each(v.rbegin(), v.rend(), &destroyFoo); 

o utilizar C++ 0x lambdas.

+0

El único comentario que agregaría es que tendría que manejar contenedores asociativos de manera diferente, ya que no puede llamar a eliminar en el 'par'. – Nim

+0

@Nim: muy buen punto. No puede iterar en claves o valores fácilmente con mapas C++, tiene que escribir un adaptador "second_iterator". –

+0

Will :: operator delete simplemente desasignar memoria o ¿también llamará al destructor? Tengo mis dudas aquí ... – Tomek

0

Una alternativa es renunciar a eliminar cosas por completo y comprometerse a utilizar un recolector de basura :) Puede probar el recopilador Boehm-Reiser-Detlefs, es estándar en Linux (libgc) y se utiliza en muchos programas complejos ahora (como gcc). También es una buena idea renunciar a RAII: fue una buena idea en ese momento, pero no funciona tan bien en la práctica. Muchos recursos se crean y destruyen de forma independiente fuera de orden con su representación.

0

Mi opinión sobre esto sería:

template<class T> 
void Destroy(T *p) 
{ 
    delete p; 
} 

template<template<typename, typename> class C, typename T1, typename T2> 
void Destroy(C<T1 *, T2> &c) 
{               
    std::for_each(c.begin(), c.end(), Destroy<T1>); 
} 

probado en g ++ 4.4.4 con el vector, y deque lista. Es posible que necesite sobrecargas adicionales de Destrucción de vacío (C < T1 *, T2 > & c) para otros contenedores y/u otras implementaciones de STL.

+0

Esto no maneja el caso de std :: some_container . Dado que, algunos_contenedores se usan con más frecuencia que algunos_contenedores , es mejor manejar char * case. – Jagannath

1

Según lo sugerido por Tomek, podemos tener una solución similar para manejar la eliminación. Una estructura hubiera sido mejor que una función gratuita.

struct Delete 
{ 
    public: 
     template<typename T> 
     void operator()(const T* ptr) const 
     { 
      delete ptr; 
     } 
     void operator()(const char* ptr) const 
     { 
      delete[] ptr; 

    } 
}; 

for_each (some_container.begin(), some_container.end(), Borrar());

+0

¿Por qué es esto mejor que una función gratuita? –

Cuestiones relacionadas