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

SL & STL C++ Discussion :

problème avec un vector d'objets contenant des iterators


Sujet :

SL & STL C++

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    49
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Novembre 2008
    Messages : 49
    Par défaut problème avec un vector d'objets contenant des iterators
    Bonjour,

    J'ai passé un moment à parcourir le forum mais n'ai pas trouvé la réponse. Ma question reprend un peu les derniers échanges de mon dernier post, mais comme cela n'a rien à voir avec le titre, je me permets d'ouvrir une nouvelle discussion.

    J'ai une classe:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    Class A{
    list<int> m_List;
    list<int>::iterator m_element;
     
    public:
    A(list<int>&)
    };
     
    A::A(list<int>& list){
    m_List = list;
    m_element=m_List.begin(); 
    }
    J'ai besoin de m_element parce que je crée ensuite un vector de A, et j'ai besoin de savoir pour chaque liste quel est l'élément courant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    Class B{
    vector<A> m_Vect;
     
    public:
    B(list<int>&)
    };
     
    B::B(list<int>& list){
    A a(list);
    vector<A> vecttemp;
    vecttemp.push_back(a);
    m_Vect=vecttemp;
    }
    Avec ce code, m_element de a pointe sur le premier élément de m_List. Quand je fais (dans le constructeur de B) vecttemp.push_back(a), m_element "ne bouge pas", alors que bien entendu, ce qui m'intéresserait, c'est qu'il indique maintenant m_Vect[0].m_List.begin(). Existe-t-il une solution sans devoir le lui écrire explicitement dans le constructeur de B?

    Merci beaucoup

  2. #2
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Par défaut
    Bonjour Manitor

    m_element => list<int>::iterator (dans un objet A)

    _Vect[0].begin() => vector<A>::iterator (dans un objet B)

    Je ne comprend pas très bien ce que tu souhaites faire.

  3. #3
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    Je rajouterais que le constructeur ne peut pas avoir un retour
    :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    B::B(list<int>& list){
    A a(list);
    vector<A> vecttemp;
    vecttemp.push_back(a);
    return vecttemp; --> Ne compile pas !
    }
    Je suis comme gbdivers, je n'arrive pas à comprendre ce que tu veux faire. Qui doit se souvenir de quoi ?

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    49
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Novembre 2008
    Messages : 49
    Par défaut
    Merci pour les réponses...

    Oui, bien sûr, pas de return dans un constructeur... Un moment d'égarement, j'ai corrigé mon code.

    Je vais essayer d'expliquer un peu mieux. J'ai donc une classe B qui est un vector<A>, où A est une liste d'entier (m_List) avec un iterator (m_element) pointant sur un élément la liste.

    Si je construis un objet B, noté b, à partir d'une liste d'entier (c'est le constructeur de B), je passe par le constructeur de A. Dans le constructeur de A, j'ai initialisé m_element comme étant le premier élément de m_List. Si je crée un A, noté a, quand je fais un push_back(a) pour en faire le premier élément de b, il fait une copie de la liste d'entier, ainsi qu'une copie de l'iterator pour l'insérer dans le vector. L'iterator pointe toujours vers a.begin(), alors que j'aimerais qu'il pointe vers le premier élément de la copie de m_List qui vient d'être ajoutée vector, soit b.m_Vect[0].m_List.begin() (deuxième faute de ma première demande que je corrige aussi...).

  5. #5
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    En préambule, je dirais que je n'aime pas trop me trimbaler des itérateurs dans des objets.
    Mais pour répondre à ton problème, tu devrais redéfinir le constructeur par copie de A (et l'opérateur = aussi) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
       A(const A&rhs_)
       :m_List(rhs_.m_List)
       {
          m_element = m_List.begin();
       }

  6. #6
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Par défaut
    Ok, c'est la suite de la discussion : http://www.developpez.net/forums/d80...ment-fonction/

    Pour info 3Darchi, c'est moi qui lui ai conseillé de mettre sa liste et son pointeur dans une classe.

    Mais le but était de garder un lien vers le dernier élément inséré (qui n'est pas forcement en première position). Dans ce cas, le mieux est d'invalider le pointeur et de ne plus l'utiliser (sinon, il faut rechercher dans la nouvelle liste l'ancien élément pointé, etc. Un peu lourd).

    Sinon, explique pourquoi tu veux garder un pointeur sur le dernier élément inséré. Il y a peut être moyen de faire autrement.

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    49
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Novembre 2008
    Messages : 49
    Par défaut
    Ah ben oui... Le constructeur par recopie... et l'opérateur =... On a toujours l'air c.. quand c'est si simple et qu'on n'y pense pas! Une petite question tout de même concernant le constructeur par copie écrit par 3Darchi, si je veux que l'iterator ne pointe pas sur l'élément du début de la nouvelle liste, mais sur l'élément qu'il pointait dans la liste de départ, je dois utiliser quelque chose comme: (??)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    A(const A&rhs_):m_List(rhs_.m_List)
       {
          m_element = m_List.begin();
          advance(m_element, distance(rhs_.m_List.begin(), rhs_.m_element);
       }
    Sinon, j'avais un peu simplifié le problème. Le but de mon programme est de trianguler des polygones. Je subdivise les côtés du polygone et j'ai donc une série de points qui constitue la première liste; je pars des deux premiers points (pt1 et pt2) et j'en crée un nouveau à l'intérieur du polygone. Ensuite je passe au couple de points suivant (l'ancien pt2 est le nouveau pt1, etc). Cette liste de points (y compris les nouveaus créés) peut s'apparenter à un front qui s'avance vers l'intérieur (du polygone). Il se trouve qu'au cours de la construction, le front peut se séparer en deux, et je me retrouve avec deux listes, d'où l'idée du vector<list> (une des deux ou les deux listes créées peuvent elles aussi se séparer en deux, etc). Je répète le même processus dans chacune des listes. Je crée donc un point dans une liste, je passe à la suivante, j'y crée un point, etc., jusqu'à revenir à la première liste où j'ai besoin de savoir quel était le dernier couple de point utilisé...

    C'est plus clair?

    Et merci beaucoup!

    PS: à la fin de mon algorithme, je ne pense pas avoir besoin de plus de 10000 points... Juste pour donner un ordre de grandeur des objets... Bon, peut-être que ça pourra augmenter... mais pas de façon pharaonique

  8. #8
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,
    Citation Envoyé par manitor Voir le message
    Ah ben oui... Le constructeur par recopie... et l'opérateur =... On a toujours l'air c.. quand c'est si simple et qu'on n'y pense pas! Une petite question tout de même concernant le constructeur par copie écrit par 3Darchi, si je veux que l'iterator ne pointe pas sur l'élément du début de la nouvelle liste, mais sur l'élément qu'il pointait dans la liste de départ, je dois utiliser quelque chose comme: (??)
    Attention, ce type de souhait a tout pour préparer une situation d'emm sans noms...

    En effet, si l'itérateur n'est pas en relation étroite avec la liste dont il est issu, tu risque, tôt ou tard (et sans doute beaucoup plus tôt que tu ne pourra l'imaginer) d'invalider ton itérateur en détruisant la liste d'origine ou en la vidant...

    Si tu ne mets pas au point un système cohérent en place, l'invalidation de l'itérateur peut passer tout à fait inaperçue et t'exploser littéralement à la figure au moment où tu t'y attend le moins

    Et je ne vois que deux solutions rapides et efficaces pour obtenir un système cohérent:
    • Soit, la liste et l'itérateur sont deux membres d'un même objet, et les comportements observés sur cet objet impliquant une modification de la liste prennent en charge la "mise à jour" de l'itérateur
    • Soit la liste fait partie d'un objet différent, mais tu dois disposer d'un système permettant de signaler à l'objet dans lequel se trouve l'itérateur qu'il a changé ( DP mediator inside :queston


    Sinon, j'avais un peu simplifié le problème. Le but de mon programme est de trianguler des polygones. Je subdivise les côtés du polygone et j'ai donc une série de points qui constitue la première liste; je pars des deux premiers points (pt1 et pt2) et j'en crée un nouveau à l'intérieur du polygone. Ensuite je passe au couple de points suivant (l'ancien pt2 est le nouveau pt1, etc). Cette liste de points (y compris les nouveaus créés) peut s'apparenter à un front qui s'avance vers l'intérieur (du polygone). Il se trouve qu'au cours de la construction, le front peut se séparer en deux, et je me retrouve avec deux listes, d'où l'idée du vector<list> (une des deux ou les deux listes créées peuvent elles aussi se séparer en deux, etc). Je répète le même processus dans chacune des listes. Je crée donc un point dans une liste, je passe à la suivante, j'y crée un point, etc., jusqu'à revenir à la première liste où j'ai besoin de savoir quel était le dernier couple de point utilisé...

    C'est plus clair?
    C'est plus clair, effectivement...

    Mais je ne crois personnellement pas que la structure liste soit réellement intéressante ici.

    Ce serait plutôt une structure prenant la forme d'un arbre binaire ou d'un graphe qu'il serait intéressant de manipuler, et dont le principe est *relativement* simple et tient dans l'utilisation d'une structure proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template <class T>
    struct TreeNode
    {
        T value;
        TreeNode* left;
        TreeNode* right;
        /* si l'utilité s'en fait sentir */
        TreeNode* parent;
    };
    (si je présente cette structure, c'est pour être en mesure de parler de manière moins abstraite )

    L'idée de base est que cette structure représentera... un élément de ta liste (un itérateur ).

    Tant que tu travailles "sur la même liste" (comprend: que tu ne souhaite pas subdiviser la liste en deux sous liste), tu te contente de travailler avec le pointeur que j'ai nommé "right" (choisi tout à fait arbitrairement).

    Si tu décide de subdiviser ta liste en deux sous liste, tu assigne le premier élément de l'une à right et l'autre à left.

    Lorsque tu parcoure ta liste, tu peux savoir pour n'importe quel élément s'il s'agit du dernier élément avant une subdivision simplement en vérifiant si left pointe sur quelque chose.

    A quelques adaptations près (entre autre le fait que right et left prennent sans doute respectivement les connotation de "plus petit" et "plus grand" ), c'est le système utilisé par la STL pour gérer les (multi)map et (multi)set

    Sauf erreur, boost apporte également sa pierre à l'édifice en proposant une implémentaiton générique (boost.Graph)
    Et merci beaucoup!

    PS: à la fin de mon algorithme, je ne pense pas avoir besoin de plus de 10000 points... Juste pour donner un ordre de grandeur des objets... Bon, peut-être que ça pourra augmenter... mais pas de façon pharaonique
    L'avantage des listes, c'est que, hormis l'espace nécessaire pour représenter les pointeurs précédents/suivants, tu ne dois pas trouver un espace contigu en mémoire libre beaucoup plus grand que celui qui est nécessaire pour contenir la valeur...

    Tu reste, quoi qu'il arrive, limité aux restrictions imposées par le système (dont la plage d'adresse mémoire accessibles), mais tu risque beaucoup moins de te voir refuser l'allocation de mémoire pour représenter un objet que... 10000 (cas d'un tableau, par exemple)
    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

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    49
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Novembre 2008
    Messages : 49
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Salut,Attention, ce type de souhait a tout pour préparer une situation d'emm sans noms...

    En effet, si l'itérateur n'est pas en relation étroite avec la liste dont il est issu, tu risque, tôt ou tard (et sans doute beaucoup plus tôt que tu ne pourra l'imaginer) d'invalider ton itérateur en détruisant la liste d'origine ou en la vidant...

    Si tu ne mets pas au point un système cohérent en place, l'invalidation de l'itérateur peut passer tout à fait inaperçue et t'exploser littéralement à la figure au moment où tu t'y attend le moins

    Et je ne vois que deux solutions rapides et efficaces pour obtenir un système cohérent:
    • Soit, la liste et l'itérateur sont deux membres d'un même objet, et les comportements observés sur cet objet impliquant une modification de la liste prennent en charge la "mise à jour" de l'itérateur
    • Soit la liste fait partie d'un objet différent, mais tu dois disposer d'un système permettant de signaler à l'objet dans lequel se trouve l'itérateur qu'il a changé ( DP mediator inside :queston
    Merci pour la réponse... Je réponds tout de suite sans avoir pris le temps de comprendre tout ce que tu me conseilles parce que je me rends compte que j'ai encore une fois mal formulé ce que je voulais...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    A(const A&rhs_):m_List(rhs_.m_List)
       {
          m_element = m_List.begin();
          advance(m_element, distance(rhs_.m_List.begin(), rhs_.m_element);
       }
    Je crois que ce code exprime assez bien ce que je souhaite, mais j'ai pu constater qu'il ne fonctionne pas.

    L'idée donc: j'ai un objet A nommé a, dont l'iterator a.m_element pointe par exemple sur le "troisième élément" de a.m_List (je veux dire par là que a.m_element=(++(++(a.m_List.begin()))). Si maintenant je crée un autre objet A nommé b à partir de a, je voudrais que b.m_List=a.m_List (normal), mais que b.m_element pointe sur le troisième élément de... b.m_List (et non sur le troisième de la liste de a, comme tu sembles l'avoir compris).

    Par contre le code que j'ai écrit ne compile pas. Si j'interprète bien les erreurs affichées, rhs_.m_List.begin() et rhs_.m_element serait deux iterators de nature différente et distance ne fonctionne pas...

    Bon, maintenant, j'étudie la suite de ta réponse

  10. #10
    Membre habitué
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Octobre 2009
    Messages : 14
    Par défaut
    bonjour,

    Tu peux mémoriser la position (en integer) que tu veux propager
    sur les copies de ton objet au lieu de mémoriser un itérateur
    qui est un vrai danger!!!...
    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
    24
    25
    26
    27
    28
    29
    30
    31
     
    Class A
    {
       list<int> m_List; 
       int m_position;
     
    public:
      A( ) : m_position( -1 )
      {
      }
      A( const A & a)
      {
         *this = a;
      }
      A &operator=( const A &a )
      {
         if( &a != this )
         {
            m_list = a.m_list;
            m_position = a.m_position;
         }
      }
     
      int mon_item_prefere( )
      {
         // J'utilise l'opérateur [ ] mais on peut aussi utiliser un std::advance
         if( m_position >= 0 && m_position < m_list.size( ) )
            return m_list[ m_position ];
         return -1; // La liste est vide.
      }
    };

  11. #11
    Membre habitué
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Octobre 2009
    Messages : 14
    Par défaut
    Désolé, dans mos post précédent, la liste n'est pas forcément vide
    si on retourne -1, cela indique simplement que la position est en dehors
    de la liste.

Discussions similaires

  1. Problème avec XSLT et du XML contenant des balises HTML
    Par xamber dans le forum XML/XSL et SOAP
    Réponses: 2
    Dernier message: 02/11/2011, 11h45
  2. Solide problème avec visualisation d'un objet 3D
    Par vdumont dans le forum OpenGL
    Réponses: 2
    Dernier message: 12/05/2006, 15h43
  3. Problème avec std::Vector
    Par mister3957 dans le forum SL & STL
    Réponses: 8
    Dernier message: 16/02/2006, 10h18
  4. [EJB2.1 Entity] [CMP] Problème avec l'extraction de la collection des fk.
    Par Last newbie dans le forum Java EE
    Réponses: 1
    Dernier message: 24/12/2005, 16h48
  5. [TTreeView] Problème avec les pointeurs d'objet
    Par BlackWood dans le forum Composants VCL
    Réponses: 2
    Dernier message: 02/07/2004, 14h31

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