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 :

Utilisation de vector de structure en C++


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2009
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2009
    Messages : 53
    Par défaut Utilisation de vector de structure en C++
    Salut à tous !!!
    Voici le défi :
    J'ai une structure de données :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    struct Links
    {
    	AtomBase &Atome;
    	int Type;
    };
    et j'ai une classe qui possède un attribut vector définit comme cela :
    Dans cette même classe, existe une fonction permettant d'ajouter un nouvel élément Links dans l'attribut vector :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void Add_Bond(AtomBase i_AtomBonded,  int BondType){ 
    	Links Link1 = {i_AtomBonded, BondType};
    	Linked.push_back(&(Link1));
     
    }
    Ca compile bien, pas de souci mais au moment de l'exécution : EXC_BAD_ACCESS !!!!
    J'ai beau chercher, je sais que ca vient de Linked.push_back(&(Link1)); qu'il aime pas mais j'arrive pas à savoir pourquoi ....
    Un petit coup de main s'il-vous-plait !! Ca fait 1h30 que je cherche à je commence à désesperer. Merci d'avance !

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 637
    Par défaut
    Salut, et bienvenue sur le forum.

    Le fait est que tu te laisse avoir à une erreur classique lorsque l'on manipule des pointeurs: tu prend l'adresse d'une variable locale à ta fonction et qui est donc détruite... lorsque l'on atteint l'accolade fermante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void Add_Bond(AtomBase i_AtomBonded,  int BondType){ 
         // ceci est une variable locale... elle n'existe que pour la
         //  durée de l'exécution de Add_bond
        Links Link1 = {i_AtomBonded, BondType}; // ca compile, ca?
     
    	Linked.push_back(&(Link1)); // tu prend l'adresse mémoire de link1, 
                                        // mais...
     
    } //link1 est détruit ici, son adresse devient donc invalide
    Tu dois donc faire en sorte que la variable continue d'exister une fois que l'on a quitté la fonction, et, pour ce faire, il n'y a pas trente six solutions: il faut passer par l'allocation dynamique de la mémoire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void Add_Bond(AtomBase i_AtomBonded,  int BondType){ 
        Links *Link1 = new Links(/*...*/);
     
    	Linked.push_back(Link1); // on ajoute le pointeur
     
    } // on a pris la responsabilité de la gestion de la durée de vie de Link1...
      // la variable continue donc d'exister...
    Par contre, cela implique qu'il faut être particulièrement vigilent pour le reste de la gestion de Linked:
    1. Si la mémoire allouée à un pointeur contenu dans Linked est libérée, la classe qui utilise Linked doit en être tenue informée et... supprimer le pointeur invalidé
    2. Lorsque l'on supprime un élément de Linked, il faut veiller à... libérer la mémoire au plus tard avant de perdre toute référence à l'emplacement mémoire utilisé, sous peine d'observer une fuite mémoire
    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

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2009
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2009
    Messages : 53
    Par défaut
    Merci Koala pour la rapidité de la réponse.
    J'ai cru voir la réponse d'un modérateur qui a enlevé son com' y'a 30 secondes disant que toutes utilisations ultérieures seraient faussées. En effet, c'est bien le cas.

    J'ai essayé l'utilisation de Links *Link1 = new Links(i_AtomBonded,BondType);
    mais ca ne marche pas. Au risque de paraitre faignant et abusif sur ce coup là, un dernier coup de main. Désolé mais je sature completement de ce probleme.

    Pour le reste je vais m'arranger dans le destructeur pour bien vérifier que tout est bien désalloué. Merci encore.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 637
    Par défaut
    Citation Envoyé par gilims Voir le message
    Merci Koala pour la rapidité de la réponse.
    J'ai cru voir la réponse d'un modérateur qui a enlevé son com' y'a 30 secondes disant que toutes utilisations ultérieures seraient faussées. En effet, c'est bien le cas.
    Effectivement, Bruno a posté une réponse et l'a retirée tout de suite après avoir remarqué (bien que n'y étant pas obligé) que j'avais répondu moins succinctement mais dans le même sens que lui...
    J'ai essayé l'utilisation de Links *Link1 = new Links(i_AtomBonded,BondType);
    mais ca ne marche pas. Au risque de paraitre faignant et abusif sur ce coup là, un dernier coup de main. Désolé mais je sature completement de ce probleme.
    Et pour cause, il n'existe aucun constructeur de Links prenant deux arguments

    J'avais perdu de vue qu'il s'agissait d'une structure pour laquelle il n'y a aucun constructeur défini par toi, ce qui fait que les Big Four sont de mise.

    Essaye peut être avec:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Links *Link1 = new Links;
    Link1->Atome = i_AtomBonded;
    Link1->Type = BondType;
    (au passage, on peut signaler que l'utilisation d'une référence pour le membre Atome de ta structure risque très fortement de poser des problèmes par la suite )
    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

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2009
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2009
    Messages : 53
    Par défaut
    Ok j'ai réussi à faire le constructeur de la structure
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Links::Links(AtomBase Atome1,int Type1) { Atome=&Atome1; Type= Type1;}
    J'ai un peu modifier la structure
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    struct Links
    {
    	Links(AtomBase Atome1,int Type1);
    public:
    	AtomBase *Atome;
    	int Type;
     
    	};

    Et le code d'ajout :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void AtomBase::Add_Bond(AtomBase i_AtomBonded,  int BondType){ 
    	Links *Link1 = new Links(i_AtomBonded,BondType);
     
    	//(*Link1).Atome = i_AtomBonded;
    	Linked.push_back(Link1);
     
    }
    Cependant, on en reviens à ce que Bruno et toi disiez, l'accès aux données pose un problème :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    cout << Linked[0].Type << endl;
    Ca continue à me renvoyer un EXC_BAS_ACCESS.

    Et là on parle même pas de l'élément Atome, mais juste d'un integer.
    Je suis désespéré .... ^^

  6. #6
    Membre émérite
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    780
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Mai 2006
    Messages : 780
    Par défaut
    Pourquoi tu utilises des pointeurs si tu ne sais pas t'en servir?

    Est-ce qu'il y en a besoin?

    Est-ce que tu as vraiment besoin d'une référence/pointeur sur AtomBase? Dans ce cas là, pourquoi tu en passes un paramètre par copie lors de la construction?

    voilà mon conseil: commence simple et réfléchis à ce que tu veux faire.

    La solution simple:
    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
     
    struct Link
    {
        Link( const AtomBase & atome, 
                int type )
        : atome_( atome),
          type_( type )
        {}
     
        AtomBase atome_;
        int type_;
    };
     
    std::vector<Link> links;
     
    void add_bond( const AtomBase & atomBonded,  int bondType)
    { 
    	links.push_back( Link( atomBonded, bondType )  ); 
    }

    Bon par contre, le C++, ce n'est pas du C, ce n'est pas du Java, va falloir revoir quelques bases (la FAQ C++ developpez.com?)

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2009
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2009
    Messages : 53
    Par défaut
    Au moins c'est de la réponse !!!
    Pourquoi tu utilises des pointeurs si tu ne sais pas t'en servir?
    Pas trop le choix pour bien gêrer le programme. Je sais que je déteste ca et que je comprends pas forcément mais c'est en forgeant qu'on devient forgeron.

    Est-ce qu'il y en a besoin?
    Est-ce que tu as vraiment besoin d'une référence/pointeur sur AtomBase?
    Définitivement oui. 2 atomes sont reliés par 1 Bond (liaison). Si je n'utilise pas des références/pointeurs, je perds sur le controle sur toute possibilité de modification.

    Dans ce cas là, pourquoi tu en passes un paramètre par copie lors de la construction?
    C'est bien ce que je me disais, mais j'avoue je n'étais pas sur.

    Bon par contre, le C++, ce n'est pas du C, ce n'est pas du Java,
    Juste pour être certain, on a le droit d'utiliser des structures de données en C++, ca je pense. Mais que vaut-il mieux faire pour ce cas là ??

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2009
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2009
    Messages : 53
    Par défaut
    Eh ben, j'aurais jamais cru m'en sortir de ce problème. Tout marche, sans aucune fuite mémoire ... ou presque. J'ai juste un détail qui va paraître nul par rapport à tout ce qu'on a dit précédemment mais bon. J'ai réussi à bien faire les liens entre atomes->liaisons et liaisons->atomes. J'arrive à lire les données des atomes dans la classe liaison, mais pas l'inverse.

    Tout ce que trouve mon compilateur à dire, avec cet AtomBase.h :
    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
     
    class BondBase;
     
    class AtomBase
    {
    private:
    	unsigned int	 Num;
    	list <BondBase*> Links;
    public:
    	void __ToString();
    	~AtomBase();
     
    	AtomBase(int _Num);
     
    	unsigned int Get_Num();
     
    	void Set_Num(unsigned int _Num);
     
    	list<BondBase*>::iterator Link;
    	void Add_link(BondBase* _Link);
    	void Unlink(BondBase* _Link);
    	bool Has_Link();
     
     
    };
    c'est : Forward declaration of 'struct BondBase' ...
    Après ca, je mets en résolu.

  9. #9
    Modérateur
    Avatar de bruno_pages
    Homme Profil pro
    ingénieur informaticien à la retraite
    Inscrit en
    Juin 2005
    Messages
    3 545
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 65
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : ingénieur informaticien à la retraite
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2005
    Messages : 3 545
    Par défaut
    Dans AtomBase.h on déclare que BondBase est une classe (class BondBase), c'est une forward declaration.

    Donc un fichier qui inclut AtomBase.h sait juste que BondBase est une classe, rien de plus, mais si le code utilise 'vraiment' la classe alors il y a un problème car sa définition est inconnue et le compilateur râle

    il suffit donc de savoir quel est le .cpp qui ne se compile pas et d'ajouter dans celui-ci un #include "BondBase"

    aucune fuite mémoire ... ou presque
    il faut apprendre à corriger cela, c'est valgrind qui les signale ?
    Bruno Pagès, auteur de Bouml (freeware), mes tutoriels sur DVP (vieux, non à jour )

    N'oubliez pas de consulter les FAQ UML et les cours et tutoriels UML

  10. #10
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2009
    Messages
    53
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2009
    Messages : 53
    Par défaut
    il faut apprendre à corriger cela, c'est valgrind qui les signale ?
    C'était juste pour le plaisir.
    En réalité j'en ai hélàs absolument aucune idée. valgrind ne marche pas avec mon système (Mac 10.6). J'utilise XCode pour trouver les fuites de mémoires, mais il avait pas réussi à me dire ce que j'attendais sur le problème précédent (problème que vous avez résolu avec Valgrind). Je vais continuer à chercher un programme équivalent qui fonctionne avec des programmes 64 bits.

    Pour le petit probleme de BondBase.h c'est réglé, il était manquant dans AtomBase.cpp.

    En tout cas, un grand merci à vous pour votre aide et vos petits conseils glissés par ci et là.

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

Discussions similaires

  1. Utilisation de vector
    Par mooglwy dans le forum SL & STL
    Réponses: 6
    Dernier message: 21/02/2007, 17h10
  2. Réponses: 19
    Dernier message: 14/11/2006, 16h45
  3. [XML] utilisations de fichiers à même structures
    Par mariemor64 dans le forum XML/XSL et SOAP
    Réponses: 9
    Dernier message: 05/10/2006, 11h29
  4. utilisation classe vector et supression de doublons
    Par vandevere dans le forum SL & STL
    Réponses: 1
    Dernier message: 30/06/2005, 11h17
  5. Problème d'utilisation de vector
    Par loupdeau dans le forum SL & STL
    Réponses: 12
    Dernier message: 28/02/2005, 12h05

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