2011-04-30 37 views
8

En mi programa C++, creo objetos en una función usando new. Estos objetos se insertan en un conjunto. Cuando quiero eliminar objetos del conjunto, utilizo un iterador en un for-loop. Cuando elimino el objeto del conjunto, aún necesito eliminar el objeto para liberar su memoria, ¿correcto? Intenté usar delete, pero luego recibí un error que decía que el puntero que se liberaba no estaba asignado. Entonces, ¿cómo puede hacerse esto?Cómo eliminar un objeto en un conjunto

Aquí es el código en la que se crea el objeto y luego insertarlo en el conjunto

set <myObject> myobjectlist; 
myObject *myobject = new myObject; 
myobjectlist.insert(*myobject); 

En otra función, trato de sacar un objeto del conjunto, y libre de su memoria:

for (set<myObject>::iterator i = myobjectlist.begin(); i != myobjectlist.end(); i++) 
if (i->myObjectID == myObjectID) 
{ 
    myobjectlist.erase(*i); 
    delete &i; 
    break; 
} 

Esto funciona bien sin la parte 'eliminar'. Lo agregué porque pensé que la memoria del objeto no se estaba liberando.

Respuesta

7

Suponiendo que está llamando al método erase() del conjunto, tenga en cuenta que esto llamará al destructor del objeto. Después de erase() su objeto, ya ha sido delete d, y por lo tanto, su segundo intento de llamar manualmente a la eliminación fallará ya que el puntero ya no está asignado.

Como referencia, ver this

+1

Según su fragmento de código, esta afirmación es engañosa. Su conjunto almacena el objeto por valor, así que lo que borra es destructivo no es lo que asignó con el nuevo. – hifier

+0

No, porque está borrando por referencia este no es el caso. Su conjunto contiene una copia del valor de su objeto original, que luego se encuentra. El valor se borra (y se destruye) del conjunto, y luego se intenta eliminar el iterador, lo que no funcionará, ya que ya no apunta a un bloque válido. –

+1

Su código no intenta eliminar el iterador, intenta eliminar la _address_ del iterador (que sigue siendo una dirección válida, simplemente no una que contiene un puntero a algo que se asignó con new). Pero este no es el punto, el código filtrará el objeto original. – hifier

2

Sí, debe eliminar los objetos que cree. Sin embargo, lo que está en su conjunto no es necesariamente lo que asignó. Por ejemplo, tal vez su conjunto contiene valores de objeto (en lugar de punteros) y su objeto asignado se está filtrando después de la inserción. Código postal

Edit: Eso fue todo. Su conjunto no almacena punteros, almacena copias de los objetos que está asignando. Retire el borrado de su bucle de borrado e insertar el objeto de esta manera:

set <myObject> myobjectlist; 
myobjectlist.insert(myObject()); 

Como alternativa, sólo que su conjunto sea set<myObject*>.

Además, borrar toma un iterador, no es necesario eliminarlo.

+0

Hacer esos cambios causa errores de compilación en for-loop. ¿Cómo debería ser cambiado? –

+0

Si almacena copias, entonces ¿está bien no usar nuevas al crear el objeto? –

+0

De cualquier manera, no puede eliminar un elemento que tenga 'erase()' d. El miembro de borrado llama al destructor del objeto y delete intentará hacer lo mismo. –

2

Aquí es lo que desea, si se asume que es necesario utilizar nuevas para asignar estos objetos:

set <myObject*> myobjectlist;  
    myObject *myobject = new myObject; 
    myobjectlist.insert(myobject); //insert the pointer, not the object 

    for (set<myObject*>::iterator i = myobjectlist.begin(); i != myobjectlist.end(); i++) { 
    if ((*i)->myObjectID == myObjectID) { 
     myobjectlist.erase(i); 
     delete *i; 
     break; 
    } 
    } 
+0

@sean, borrar no incrementa el iterador. De hecho, borrar toma este parámetro por valor, por lo que no puede tener ningún efecto en su objeto iterador. – hifier

+0

Para mayor claridad, el borrado de llamadas cambiará el conjunto y, por lo tanto, invalidará el iterador para su uso posterior dentro del conjunto. Sin embargo, el iterador mismo permanece sin cambios y aún se puede usar para recuperar el puntero al objeto que acaba de borrarse. – hifier

+0

mi confusión se basa en la implementación de vs2010 de erase - set :: erase devuelve nulo, pero se implementa a través de _Tree :: erase que devuelve un iterador incrementado –

1

Si necesita una lista de punteros, utilizar una lista de punteros inteligentes. Use un algoritmo estándar para encontrar el elemento correcto y borrarlo de la lista.

#include <set> 
#include <boost/shared_ptr.hpp> 
#include <boost/bind.hpp> 

using namespace boost; 

typedef boost::shared_ptr<MyObject> t_object; 
std::set<t_object> myObjectList; 
myObjectList.insert(t_object(new MyObject)); 

std::set<t_object>::iterator item = std::find_if(
    myObjectList.begin(), 
    myObjectList.end(), 
    bind(&MyObject::myObjectID, _1)== myObjectID); 
if(item!=myObjectList.end()) 
    myObjectList.erase(item); 
Cuestiones relacionadas