IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C++ Discussion :

supprimer un élément d'une liste avec erase


Sujet :

C++

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    219
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 219
    Points : 97
    Points
    97
    Par défaut supprimer un élément d'une liste avec erase
    Bonsoir,

    Je voudrais effacer un élément dans une liste. L'élément en question est un événement et est constitué de plusieurs attributs.
    Voici ma fonction Delete, qui se trouve dans la classe eventlist :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    void eventlist::DeleteEvent(){
    string nameeventtodelete;
     
    cout<<"Which name do you want to erase?\n";
    cin >>nameeventtodelete;
     
    event eventobj(nameeventtodelete);
     
    for (list<event>::iterator it = mylistofevent.begin (); it != mylistofevent.end (); ++it) {
    	if (nameeventtodelete==eventobj.getNameEvent()){
    		mylistofevent.erase( eventobj  );
    	}
    }
     
    PrintEventList();
    }
    Je ne comprends pas trop l'erreur qu'il me donne : un problème avec la fonction erase, mais je sais pas quoi précisément. Je sais pas si je peux demander d'effacer un objet, comme je le fais, mais je vois pas à quoi d'autre appliquer la fontion erase...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    eventlist.cc: In member function ‘void eventlist::DeleteEvent()’:
    eventlist.cc:112: erreur: no matching function for call to ‘std::list<event, std::allocator<event> >::erase(event&)’
    /usr/lib/gcc/i386-redhat-linux/4.3.0/../../../../include/c++/4.3.0/bits/list.tcc:109: note: candidats sont: typename std::list<_Tp, _Alloc>::iterator std::list<_Tp, _Alloc>::erase(std::_List_iterator<_Tp>) [with _Tp = event, _Alloc = std::allocator<event>]
    /usr/lib/gcc/i386-redhat-linux/4.3.0/../../../../include/c++/4.3.0/bits/stl_list.h:1026: note:                 std::_List_iterator<_Tp> std::list<_Tp, _Alloc>::erase(std::_List_iterator<_Tp>, std::_List_iterator<_Tp>) [with _Tp = event, _Alloc = std::allocator<event>]
    make: *** [eventlist.o] Erreur 1
    Voici mon fichier eventlist.hh :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    using namespace std;
     
    class eventlist{
     
    private:
    	list<event> mylistofevent;
     
    public:
    	eventlist();
    	void PrintEventList();
    	void AddEvent();
    	void DeleteEvent();
    	void PrintEventListFile();
    };
    Et enfin event.hh

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    class event{
     
    private :
    	string nameevent;
    	int eventnumber;
    	string organiser;
    	string departorganiser;
    	string date;
    	string place;
     
    public:
    	event();
    	event(string);
    	event(int, string,string,string,string,string);
    	string getNameEvent();
    	int getNum();
    	string getNameOrganiser();
    	string getDepartOrganiser();
    	string getDate();
    	string getPlace();
     
    };
    Je sais pas si tout ce code est nécessaire à la compréhension de mon problème, mais j'espère que vous vous y retrouverez !
    Merci

  2. #2
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut
    Bonjour,

    Commence par lire ceci, et dis nous si ça bloque : http://cpp.developpez.com/faq/cpp/?p...ssion_elements
    Cours : Initiation à CMake
    Projet : Scalpel, bibliothèque d'analyse de code source C++ (développement en cours)
    Ce message a été tapé avec un clavier en disposition bépo.

  3. #3
    Membre expérimenté

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Points : 1 543
    Points
    1 543
    Par défaut
    Salut,

    La méthode erase prend un itérateur et non un élément.

    MAT.

  4. #4
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut
    C'est surtout qu'avec une liste, on utilise remove() !
    Cours : Initiation à CMake
    Projet : Scalpel, bibliothèque d'analyse de code source C++ (développement en cours)
    Ce message a été tapé avec un clavier en disposition bépo.

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    219
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 219
    Points : 97
    Points
    97
    Par défaut
    Merci pour les liens, j'ai vu que je pouvais utiliser la fonction remove_if. Cette fonction s'applique à un bool et pas à un itérateur comme erase. J'ai reécris ma fonction :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    void eventlist::DeleteEvent(){
    string nameeventtodelete;
     
    event eventobj(nameeventtodelete);
     
    cout<<"Which name do you want to erase?\n";
    cin >>nameeventtodelete;
     
    bool eventlist::equal(string nameeventtodelete){
    	return (nameeventtodelete==eventobj.getNameEvent());
    	}
     
    for (list<event>::iterator it = mylistofevent.begin (); it != mylistofevent.end (); ++it) {
    	mylistofevent.remove_if( equal  );
     
    }
     
    PrintEventList();
    }
    qui ne marche pas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    eventlist.cc: In member function ‘void eventlist::DeleteEvent()’:
    eventlist.cc:112: erreur: a function-definition is not allowed here before ‘{’ token
    eventlist.cc:117: erreur: no matching function for call to ‘std::list<event, std::allocator<event> >::remove_if(<unresolved overloaded function type>)’
    make: *** [eventlist.o] Erreur 1
    Mon problème ne vient-il pas du fait que je compare un nom saisi avec un nom dans une liste mais que je cherche à effacer tout un objet, qui n'est pas constitué que d'un nom? Parce que là, j'ai bien l'impression de demander d'effacer que le nom ...
    Ma condition me permet de trouver ce que je veux effacer, mais n'est pas ce que je veux effacer

  6. #6
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut
    remove_if() ne prend pas un booléen, mais un prédicat. C'est donc plus compliqué que ça.

    Pour faire simple, commence par utiliser la fonction membre remove() (et pas remove_if()).
    La fonction remove() accepte un objet de type T, correspondant au paramètre de ta liste (std::list<T>). La fonction parcourt la liste jusqu'à trouver un objet égal à celui que tu as passé en paramètre (operator==). Une fois cet objet trouvé, il est supprimé.
    Par conséquent, gère plutôt une liste de pointeurs d'event (std::list<event*>) au lieu d'une liste d'events. Ça évitera les appels aux fonctions de test d'égalité.

    En bref :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    std::list<event*> events;
     
    void remove_event(const event& e)
    {
        events.remove(&e);
    }
    Essaie ça et quand ça fonctionnera, on utilisera remove_if() ensemble si tu veux (qui est plus adapté à ton cas puisque tu veux supprimer un élément en le recherchant par son nom).
    Cours : Initiation à CMake
    Projet : Scalpel, bibliothèque d'analyse de code source C++ (développement en cours)
    Ce message a été tapé avec un clavier en disposition bépo.

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    219
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 219
    Points : 97
    Points
    97
    Par défaut
    Merci FlorianGoo pour le code, j'ai essayé, mais je ne suis pas arrivée à le faire marcher.
    J'ai appris que dans ce projet, il ne faut pas utiliser de pointeurs... Je vais reessayer avec la méthode erase, j'ai vu quelqu'un écrire cette fonction avec cette méthode, alors, je vais m'atteler à cette tâche

  8. #8
    Membre éclairé
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Points : 858
    Points
    858
    Par défaut
    En fait, à terme il faudrait que tu utilises la fonction membre remove_if(). Mais comme c'est un peu compliqué pour un débutant, je voulais juste m'assurer que tu saches déjà utiliser la fonction membre remove().
    Cours : Initiation à CMake
    Projet : Scalpel, bibliothèque d'analyse de code source C++ (développement en cours)
    Ce message a été tapé avec un clavier en disposition bépo.

  9. #9
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    219
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 219
    Points : 97
    Points
    97
    Par défaut
    ça y est, j'ai une fonction qui me permet d'effacer un élément de ma liste

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    void eventlist::DeleteEvent(int evttodestroy){
     
    list<event>::iterator it;
    for (it = mylistofevent.begin (); it != mylistofevent.end (); ++it) { 
     
    	if ((*it).getNum() == evttodestroy ) {
    		break;
    	}
    }
    mylistofevent.erase(it); 
     
    }
    Il ne faut surtout pas mettre la fonction erase dans la boucle for sinon on efface un element sur une liste dont on modifie la taille...
    Par contre, je ne comprends pas pourquoi l'itérateur garde en mémoire l'adresse de l'élément qu'on recherche car quand on le trouve, on sort de la boucle if à cause du break, mais il me semble qu'on continue dans le for... dc it devrait contenir l'adresse du dernier itérateurr, non?
    Je doute que cette méthode soit du très bon C++ mais la date de remise de mon projet approche, alors, ça m'ira!
    merci à tous pour votre aide

  10. #10
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Points : 50 367
    Points
    50 367
    Par défaut
    Une petite remarque dans ton code, si tu ne trouve pas l'élément à supprimer, ta boucle se termine et ton itérateur vaut mylistofevent.end() et tu fais un erase() avec. Je suppose que c'est testé par la classe mais c'est pas très beau/safe.

    Pourquoi pas un truc comme cela:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    void eventlist::DeleteEvent(int evttodestroy)
    {
       for(list<event>::iterator it = mylistofevent.begin (); it != mylistofevent.end (); ++it)
       {
          if ((*it).getNum() == evttodestroy )
          {
             // destruction de l'élément
             mylistofevent.erase(it);
     
             // et on quitte la boucle immédiatement puisqu'on a trouvé
             break;
          }
       }
    }
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  11. #11
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    219
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 219
    Points : 97
    Points
    97
    Par défaut
    Merci ram-0000, ta fonction marche parfaitement, et est plus élégante

  12. #12
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    Alternativement, le fait de changer de boucle donnerait encore quelque chose de plus beau...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    list<event>::iterator it = mylistofevent.begin(); // on prend le premier
                                                      // événement
    while(it!=mylistofevent.end() && (*it).getNum() == evttodestroy)
    {
        /* si on entre dans la boucle, c'est qu'il faut passer à 
         * l'itérateur suivant */
        ++it;
    }
    /* arrivé ici, il faut juste s'assurer que nous avons bien l'élément 
     * à supprimer */
    if((*it).getNum()==evttodestroy)
    {
        mylistofevent.erase(it);
    }
    Si la mémoire allouée aux événements est allouée dynamiquement, cela devient
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    if((*it)->getNum() == evttodestroy)
    {
        delete (*it);
        mylistofevent.erase(it);
    }
    Evidemment, l'idéal resterait quand même de s'atteler à remove_if
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  13. #13
    Membre régulier
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    219
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 219
    Points : 97
    Points
    97
    Par défaut
    Merci pour ces solutions, celle avec le delete est vraiment "optimisée".
    Citation Envoyé par koala01 Voir le message
    Evidemment, l'idéal resterait quand même de s'atteler à remove_if
    ça sera pour mon prochain projet !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 7
    Dernier message: 23/04/2008, 10h21
  2. Réponses: 12
    Dernier message: 12/03/2007, 16h58
  3. Réponses: 12
    Dernier message: 04/03/2007, 11h43
  4. Réponses: 3
    Dernier message: 25/10/2006, 19h08
  5. Supprimer des éléments d'une liste
    Par espadon1 dans le forum Langage
    Réponses: 2
    Dernier message: 31/05/2006, 15h08

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo