10
votes

Comment supprimer un objet dans un ensemble

Dans mon programme C ++, je crée des objets dans une seule fonction en utilisant nouveau. Ces objets sont insérés dans un ensemble. Lorsque je veux supprimer des objets de l'ensemble, j'utilise un itérateur dans une boucle pour la boucle. Lorsque je supprimai l'objet de l'ensemble, j'ai toujours besoin de supprimer l'objet pour libérer sa mémoire, corriger? J'ai essayé d'utiliser Supprimer, mais je reçois alors une erreur indiquant que le pointeur étant libéré n'a pas été attribué. Alors comment cela peut-il être fait?

Voici le code où je crée l'objet, puis insérez-le dans l'ensemble xxx

dans une autre fonction, j'essaie de supprimer un Objet à partir de l'ensemble, libérer sa mémoire: xxx

Cela fonctionne bien sans la partie "Supprimer". Je l'ai ajouté parce que je pensais que la mémoire de l'objet n'était pas libérée.


0 commentaires

4 Réponses :


3
votes

Oui, vous devez supprimer des objets que vous créez. Cependant, ce qui est dans votre ensemble n'est pas nécessairement ce que vous avez alloué. Par exemple, peut-être que votre ensemble contient des valeurs d'objet (plutôt que des pointeurs) et votre objet alloué est fui après insertion. Code postal.

Edit: C'était ça. Votre ensemble ne stocke pas les pointeurs, il stocke des copies des objets que vous allociez. Supprimez la suppression de votre boucle d'effacement et insérez l'objet comme celui-ci: p>

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


4 commentaires

Faire de ces changements provoque des erreurs de compilation dans la boucle. Comment devrait-il être changé?


Si cela stocke des copies, alors peut-être que c'est bien de ne pas utiliser de nouveau lors de la création de l'objet?


De toute façon, vous ne pouvez pas puis supprimer un élément que vous avez effacer () d. L'élément efface appelle le destructeur de l'objet et supprimera tentera de faire la même chose!


Droite - Supprimez le nouveau et le Supprimer.



10
votes

En supposant que vous appelez la méthode ERASE (CODE> ERASE () de l'ensemble, note que Cela appellera le destructeur de l'objet pour vous . Après votre Erase () Votre objet, il a déjà été Supprimer D, et donc votre deuxième tentative d'appel manuellement supprimer échouera car le pointeur n'est plus attribué.

Pour référence, voir Ce


6 commentaires

Basé sur son extrait de code, cette déclaration est trompeuse. Son ensemble stocke l'objet par la valeur, de sorte quelle effacement détruit n'est pas ce qu'il a alloué avec nouveau.


Non, parce qu'il supprime par référence ce n'est pas le cas. Son ensemble contient une copie de la valeur de son objet d'origine, qui est ensuite trouvée. La valeur est effacée (et destructée) à partir de l'ensemble, puis l'itérateur est tenté d'être supprimé - ce qui ne fonctionnera plus, car il ne pointe plus d'un bloc valide.


Son code ne tente pas de supprimer l'itérateur, il tente de supprimer l'adresse de l'itérateur (qui est toujours une adresse valide, tout simplement pas une personne qui contient un pointeur sur quelque chose qui a été attribué à nouveau). Mais ce n'est pas le point, le code va fuir l'objet d'origine.


C'est cependant le point - vous ne pouvez pas supprimer quelque chose si cela n'a pas été attribué à nouveau. L'ensemble supprime la copie et en essayant de supprimer l'itérateur, l'erreur est lancée.


@Ben, ce n'est pas le point de sa question comme je l'ai pris. Même si nous avons corrigé cela, cela fuit encore la mémoire. L'objectif est-il de le faire courir ou de le rendre correct?


Quand j'ai initialement répondu à la question, il n'y avait pas de code - juste tout avant le "Alors, comment cela peut-il être fait?" question. À ce moment-là, la réponse était «Vous ne pouvez pas (ou ne devrait pas)», sauvegardé par ce qui précède. Maintenant qu'il y a du code, j'apprécie que la question ait peut-être changé. Mon approche étiperait toujours la mémoire, mais courait, ce qui était ce que j'ai interprété l'OP comme demandant à l'origine.



3
votes

Voici ce que vous voulez, en supposant que vous devez utiliser de nouvelles pour allouer ces objets:

  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;
    }
  }


3 commentaires

@san, Effacer n'écrége pas l'itérateur. En fait, Effacer prend ce paramètre par valeur, de sorte qu'il ne peut avoir aucun effet sur votre objet Itérateur.


Pour plus de clarté, appeler Erase changera l'ensemble et invalidera donc l'itérateur pour une utilisation ultérieure dans l'ensemble. Cependant, l'itérateur lui-même reste inchangé et peut toujours être utilisé pour récupérer le pointeur sur l'objet qui a été effacé.


ma confusion était basée sur la mise en œuvre de l'effacement VS2010 :: Effacer les retours vides, mais il est mis en œuvre via _tree :: Effrez qui renvoie un itérateur incrémené



2
votes

Si vous avez besoin d'une liste de pointeurs, utilisez une liste des pointeurs intelligents. Utilisez un algoritm std pour trouver l'élément correct et l'effacez de la liste. xxx


0 commentaires