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 :

Boucle de suppression d'éléments d'une Map


Sujet :

C++

  1. #1
    Membre actif
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    577
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 577
    Points : 256
    Points
    256
    Par défaut Boucle de suppression d'éléments d'une Map
    Bonjour,
    j'ai un petit problème avec ce code :

    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
    void CTest::PurgeRequest ()
    {       
    	CSingleLock Lock (&m_semRequest, TRUE);
     
    	std::map<DWORD, HCALL>::iterator it;
     
    	for( it = m_mapWaitReq.begin(); it != m_mapWaitReq.end(); it ++)
    	{		
    	       if( GetInCallFromHandle( (*it).second ) == NULL )
                            m_mapWaitReq.erase( it );
    	}
     
    	return;
     
    }// CTest::PurgeRequest

    Ma suppression n'est pas correcte, et fait planter si je supprime le dernier élément.
    J'ai bien regardé cette page :
    http://c.developpez.com/faq/cpp/?pag...ssion_elements
    mais cela ne semble pas adapté au parcours des map ...

    Merci de votre aide.

  2. #2
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    Avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    m_mapWaitReq.erase( it->first );
    ça donne quoi?

  3. #3
    Membre éclairé Avatar de ZaaN
    Inscrit en
    Novembre 2005
    Messages
    819
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 819
    Points : 661
    Points
    661
    Par défaut
    Personnelement, j ai l'habitude de mettre a jour l'iterateur a partir de la methode erase:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    it = m_mapWaitReq.erase( it->first );

  4. #4
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Sauf que std::map::erase renvoie un void (ne me demandez pas pourquoi). Sous Visual C++ il me semble qu'il renvoie bien un itérateur, mais ce n'est pas standard.

    Solution de rechange :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    for( it = m_mapWaitReq.begin(); it != m_mapWaitReq.end(); )
    {		
        if( GetInCallFromHandle( (*it).second ) == NULL )
            m_mapWaitReq.erase( it++ );
        else
            ++it;
    }

  5. #5
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    avec(clé comme paramètre), la map fait son propre algo de suppression donc ça marche. Par contre, j'ai peur que ce soir un peu plus lent...

  6. #6
    Membre actif
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    577
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 577
    Points : 256
    Points
    256
    Par défaut
    Merci à vous !

    Effectivement sous VC++ il renvoie un iterateur. Bon j'aurais pu utiliser comme ça, car je suis sous VC++, mais comme j'avais lu dans la faq que ça ne renvoie rien, j'avais peur de la portabilité ....

    Laurent, une question : pourquoi utilises-tu un coup it++, un coup ++it ? y a -til une raison ?

  7. #7
    Membre actif
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    577
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 577
    Points : 256
    Points
    256
    Par défaut
    Citation Envoyé par poukill
    avec(clé comme paramètre), la map fait son propre algo de suppression donc ça marche. Par contre, j'ai peur que ce soir un peu plus lent...
    Non, ça ne marche pas non plus, car je retourne sur le it++ qui plante

  8. #8
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Citation Envoyé par poukill
    avec(clé comme paramètre), la map fait son propre algo de suppression donc ça marche. Par contre, j'ai peur que ce soir un peu plus lent...
    A mon avis ça ne marchera pas plus, la version de erase qui prend une clé en paramètre recherche l'itérateur avec find puis appelle la version d'erase prenant un itérateur. Puisqu'on fait le parcours nous-même ici, autant passer directement l'itérateur à erase.

    De toute façon ce n'est pas un problème de fonction, mais de logique : si tu supprimes un élément, tu ne peux pas demander à ce que l'itérateur qui pointait dessus soit encore valide après.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 627
    Points : 30 692
    Points
    30 692
    Par défaut
    Salut

    A moins de supprimer les éléments au fur et à mesure de leur invalidation (chaque fois qu'il y en a un dont la valeur passe à NULL), il n'y a qu'une solution qui tient dans l'algorithme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    iterateur <- map.begin()
    Tant que iterateur!= map.end()
    |    si iterateur->second=NULL
    |    |    suppression iterateur
    |    |    iterateur <- map.begin()
    |    SINON
    |    |    iterateur ++
    |    FIN SI
    FIN TANT
    Mais cela nous emmenera à une complexité en N!

  10. #10
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Citation Envoyé par koala01
    A moins de supprimer les éléments au fur et à mesure de leur invalidation (chaque fois qu'il y en a un dont la valeur passe à NULL), il n'y a qu'une solution qui tient dans l'algorithme
    La solution que j'ai donnée ici est quand même censée marcher. Mais bon on dirait que personne ne l'a vue.

  11. #11
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    Si si... Bien sûr...
    Moi je faisais que poser une question !!!

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 627
    Points : 30 692
    Points
    30 692
    Par défaut
    Autant pour moi, laurent, je ne l'avais effectivement pas vue...

    Mais, disons, que de manière générale, je suis quelque peu allergique à l'idée de créer une boucle incrémentale sans fournir les trois valeurs explicitement

    les for( ;; ) for(i=0;i<n; ) et autres for(i=0,j=0;i<n;i++,j++) du meme style, pourtant autorisées par le C++, ont tendance à me faire hérisser le poil

  13. #13
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Rien n'empêche de la remplacer par un while

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 627
    Points : 30 692
    Points
    30 692
    Par défaut
    Je préfère, en effet, et tu remarqueras que c'est en substance le but de l'algorithme prorosé

  15. #15
    Membre actif
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    577
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 577
    Points : 256
    Points
    256
    Par défaut
    Citation Envoyé par Laurent Gomila
    La solution que j'ai donnée ici est quand même censée marcher. Mais bon on dirait que personne ne l'a vue.
    Heu perso, je l'ai bien vue, et même que depuis 1 heure je m'en sers !!
    MERCI !

    Effectivement, on peut aussi faire un while ... mais qui fait repartir à chaque suppression au début
    Bon, dans mon cas, c'est pas trés dérangeant ... mais de manière générale si.
    Je préfère donc fournir 2 valeurs dans un for, plutôt qu'avoir un while + lent.

  16. #16
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Le while est équivalent au for, c'est juste écrit différemment.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    it = m_mapWaitReq.begin();
    while (it != m_mapWaitReq.end())
    {
        if( GetInCallFromHandle( (*it).second ) == NULL )
            m_mapWaitReq.erase( it++ );
        else
            ++it;
    }

  17. #17
    Membre actif
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    577
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 577
    Points : 256
    Points
    256
    Par défaut
    Citation Envoyé par koala01
    Salut

    A moins de supprimer les éléments au fur et à mesure de leur invalidation (chaque fois qu'il y en a un dont la valeur passe à NULL), il n'y a qu'une solution qui tient dans l'algorithme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    iterateur <- map.begin()
    Tant que iterateur!= map.end()
    |    si iterateur->second=NULL
    |    |    suppression iterateur
    |    |    iterateur <- map.begin()
    |    SINON
    |    |    iterateur ++
    |    FIN SI
    FIN TANT
    Mais cela nous emmenera à une complexité en N!
    Oui oui en effet, mais ce n'est pas ce que l'algo de Koala (cf. ci-dessus) sous-entendait ...

  18. #18
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    78
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Janvier 2004
    Messages : 78
    Points : 62
    Points
    62
    Par défaut
    Bonjour,

    Désolé de relancer un sujet aussi ancien, mais je ne vois pas la différence que vous faites entre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    for( it = m_mapWaitReq.begin(); it != m_mapWaitReq.end(); )
    {		
        if( GetInCallFromHandle( (*it).second ) == NULL )
            m_mapWaitReq.erase( it++ );
        else
            ++it;
    }
    et

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    for( it = m_mapWaitReq.begin(); it != m_mapWaitReq.end(); )
    {		
        if( GetInCallFromHandle( (*it).second ) == NULL )
            m_mapWaitReq.erase( it );
     
        ++it;
    }
    ou encore

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    for( it = m_mapWaitReq.begin(); it != m_mapWaitReq.end(); it++)
    {		
        if( GetInCallFromHandle( (*it).second ) == NULL )
            m_mapWaitReq.erase( it );
    }

  19. #19
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    78
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Janvier 2004
    Messages : 78
    Points : 62
    Points
    62
    Par défaut
    Bon ce fût bref et je me réponds moi-même

    erase(it++) crée une copie de it qu'il passe à erase, l'incrémentation est effectuée sur sa valeur originale. D'où la différence entre
    erase(it);
    it++;
    et
    erase(it++);

    Cela répond aussi du coup à la question de olive_le_malin posée plus haut : it++ réalise une copie alors que ++it ne passe pas par cette étape. C'est pour cela qu'il vaut mieux utiliser ++it quand c'est possible pour question de performances.

    Donc ok pour :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    for( it = m_mapWaitReq.begin(); it != m_mapWaitReq.end(); )
    {		
        if( GetInCallFromHandle( (*it).second ) == NULL )
            m_mapWaitReq.erase( it++ );
        else
            ++it;
    }

  20. #20
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Sauf que la question originale a été posté en 2007. Depuis, le C++11 est passé par là et le standard a été corrigé pour qu'erase() retourne l'itérateur suivant. Il est donc maintenant recommandé pour plus de clarté d'écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    for( it = m_mapWaitReq.begin(); it != m_mapWaitReq.end(); )
    {		
        if( GetInCallFromHandle( (*it).second ) == NULL )
            it = m_mapWaitReq.erase(it);
        else
            ++it;
    }

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

Discussions similaires

  1. [XL-2010] Gérer les suppressions d'éléments dans une collection et une double boucle
    Par Rayanea dans le forum Macros et VBA Excel
    Réponses: 4
    Dernier message: 22/10/2013, 09h08
  2. pb de suppression d'éléments avec une map
    Par pada51 dans le forum SL & STL
    Réponses: 2
    Dernier message: 08/08/2007, 14h36
  3. Réponses: 4
    Dernier message: 24/05/2007, 16h37
  4. [Thread] Synchroniser tous les éléments d'une map
    Par Monorom dans le forum Concurrence et multi-thread
    Réponses: 7
    Dernier message: 02/04/2007, 12h33
  5. Suppression d' éléments dans une liste.
    Par conan76 dans le forum ASP.NET
    Réponses: 3
    Dernier message: 02/03/2007, 09h33

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