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 :

Graphe d'objet et désallocations


Sujet :

C++

  1. #1
    screetch
    Invité(e)
    Par défaut Graphe d'objet et désallocations
    Bonjour, j'ai quelques problèmes de conception avec mon graphe d'objet et je me demande comment résoudre. Je me retrouve toujours avec des problèmes d'ordre d'initialisation ou de désallocation. J'esplik:

    j'ai deux types d'objet: des ClassInfo (représentant des informations d'une classe que l'on peut demander au runtime) et des PropertyInfo (pour obteir des membres d'une instance)

    les ClassInfo possèdent donc des PropertyInfo pour chaque membre.
    De plus, les ClassInfo possèdent un membre parent, qui pointe sur le ClassInfo de la classe parent.

    Je dispose dans ma boîte a outil de deux types de pointeurs intelligent: les ref<XXX> qui sont des pointeurs avec un refcount, et les weak<XXX> qui ne prolongent pas la vie de l'objet.
    Le destructeur des classes renvoie une assertion si l'on désalloue un objet qui a encore des références faibles dessus; c'est a dire qu'avant de désallouer d'un objet il faut vérifier qu'il n'y a plus aucune référence weak dessus (dangling pointer). Je ne souhaite pas du tout me débarasser de ce système.

    Jusque là jespère que vous suivez encore

    Bon ensuite les PropertyInfo contiennent leur type, pour simplifier le ClassInfo qui représente la classe.

    par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class A
    {
    };
     
    class B
    {
      public:
        A a;
    };
    on aura donc ici:
    un classinfo pour A
    un classinfo pour B qui contient
    un propertyinfo pour a qui utilise le classinfo de A


    Le problème c'est que le graphe d'objet qui est donc un graphe représentant la structure du code, a des cycles et autres joyeusetés qui le rendent difficile a créer.

    Par exemple, on peut avoir cela:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    class A
    {
      A* a;
    };
    (oui parce que les pointeurs sont autorisés quand même)

    on se retrouve donc avec un ClassInfo A, qui possède un PropInfo a, qui pointe de nouveau sur A.

    Alors ma première expérience a donc été que le ClassInfo "possède" les propinfo, et qu'ensuite le propinfo a une référence faible sur le ClassInfo.
    Cela résout les cycles (et il ne peut pas y avoir de cycles entre les classes donc ca marche, puisque l'héritage est un arbre)
    Pan! problème résolu
    Et ben non dans le cas:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class A
    {
    };
     
    class B
    {
      public:
        A a;
    };
    il se peut très bien que A soit détruit avant B. La proprieté a sera donc detruite en même temps que B. Mais si A est detruit avant la propriété a, alors le PropInfo va se plaindre que son type est en train d'être désalloué

    En gros soit j'ai un cycle et donc un leak mémoire, soit les PropInfo pointent sur des objets décédés. Je n'arrive pas trop a résoudre ca correctement any help welcome



    Pour info, les ClassInfo et PropInfo sont extrait par un script python, qui parse les sources C++ et génère un autre fichier C++ qui contient les définition des classes. J'ai donc un bon contrôle du code et ca peut être compliqué puisque c'est automatiquement généré.

  2. #2
    screetch
    Invité(e)
    Par défaut
    bon j'ai finalement trouvé un moyen de faire en faisant deux initialisations et deux déinitialisations
    d'abord on crée les ClassInfo (vides)
    on peut donc créer l'arborescence
    puis une deuxieme initialisation ajoute les PropInfo a tous les ClassInfo

    a la fin, le contraire: on commence par retirer toute les propriétés des metaclasses
    puis une deuxieme passe les detruit, en etant sûr cette fois qu'aucune propriété ne pointe sur un ClassInfo

    c'est un poil plus compliqué dans la pratique mais c'est comme ca que ca marche. Ni leak ni crash

  3. #3
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Mais ça t'oblige à tout désallouer d'un bloc, non ?

    A part ça, j'aime bien la notion de weak telle que tu la décris : Il est faible parce qu'il ne prolonge pas la vie de l'objet, mais si jamais on a tué l'objet alors qu'il était encore là, le programme s'arrête...

    Une autre solution à laquelle j'avais pensé pour ton problème serait de mettre uniquement des ref<xxx> et de faire un mini garbage collector pour ces objets en particulier, qui quand il détecte qu'un groupe n'est plus utile passe tous les refs à 0.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  4. #4
    screetch
    Invité(e)
    Par défaut
    Non ca ne désalloue pas tout d'un bloc, c'est assez compliqué...

    pour tout expliquer le problème principal etait le suivant:

    ClassInfo A a une propriété b, de type B (donc ClassInfo B)
    A est créé
    b a besoin de B donc B est créé
    b est créé

    donc le PropInfo est initialisé APRES A et B
    mais lors de la deinitialisation, b appartient a A donc b est detruit en même temps que A
    B etant créé le dernier, B sera detruit le premier, avant A, avant sa propriété, d'ou l'erreur.
    La solution est donc bien d'avoir l'ordre d'initalisation/de déinitialisation:
    A est créé
    B est créé
    b est ajouté a A
    ****
    b est retiré de A
    B est détruit (cette fois ci de manière safe)
    A est detruit (bien qu'il ne contienne plus de propriété)


    ajouté a cela que A et B peuvent être dans des fichiers séparés, ca fait une belle soupe. Mais malgré la complexité, c'est maintenant "demontré" que c'est correct! ouf! (enfin si vous avez suivi)

    je vous fais grâce du code généré... heureusement qu'il n'est pas ecrit à la main!
    donc les ordres d'initialisation ou de deinitialisation ne sont pas par blocs, c'est la lazy initalisation qui va définir l'ordre, et le cleanup se fera dans l'ordre inverse.

    (je sais a quoi m'attendre avec les variables initialisées avant main, je savais que ca allait être le bordel...)



    Sinon les weak pointers, c'est une notion très stricte et ca ne fait pas de cadeau. J'ai décidé ca au tout début parce que je pense qu'a plusieurs reprises ca m'a évité des bugs très complexes a résoudre. Mais parfois ca claque pour une broutille, comme une variable locale qui traine plus bas dans la pile. Mais je me dis, au pire, c'aurait été un pointeur nu a la place, il serait mort sans me prévenir et peut être ca aurait crashé a la place...

  5. #5
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Citation Envoyé par screetch Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class A
    {
    };
     
    class B
    {
      public:
        A a;
    };
    il se peut très bien que A soit détruit avant B. La proprieté a sera donc detruite en même temps que B. Mais si A est detruit avant la propriété a, alors le PropInfo va se plaindre que son type est en train d'être désalloué .
    Je suis d'accord avec JolyLoic, ton usage des weak pointers est louche : dans le scénario que tu décris, vu que le PropInfo possède un weak, pourquoi se plaindrait-il ? Il n'a qu'à ne rien dire et ne râler que dans le cas ou tu tentes de te servir de ce weak et que l'objet a été détruit. Le weak n'est pas qu'un pointeur qui ne prolonge pas la vie de l'objet, il est aussi censé être capable de te dire si l'objet existe encore ou pas.

    Du coup je ne comprend pas pourquoi tu as un problème (et pourtant j'ai bien suivi )
    Find me on github

  6. #6
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Le weak_ptr de boost (ou celui du TR1) sont effectivement capable de dire si un objet existe toujours, mais la majorité des implémentations ne vont pas jusque là. A moins que screetch ait utilisé l'un des deux weak_ptr cités, il y a de fortes chances qu'il soit dans le second cas.

    (et franchement, je le comprends : faire un weak_ptr associé à un shared_ptr qui est capable de dire si le shared_ptr existe toujours dans un environnement multithread, c'est une horreur).
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  7. #7
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Citation Envoyé par Emmanuel Deloget Voir le message
    (et franchement, je le comprends : faire un weak_ptr associé à un shared_ptr qui est capable de dire si le shared_ptr existe toujours dans un environnement multithread, c'est une horreur).
    Mais s'il n'est pas en multithread ? Peut être que dans son cas, ça le tirerai d'affaire.

    J'ai du mal à saisir l'utilité d'un weak pointer si on ne peut pas tester l'existence de l'objet. Quelle différence avec un pointeur nu ?
    Find me on github

  8. #8
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par jblecanard Voir le message
    Mais s'il n'est pas en multithread ? Peut être que dans son cas, ça le tirerai d'affaire.

    J'ai du mal à saisir l'utilité d'un weak pointer si on ne peut pas tester l'existence de l'objet. Quelle différence avec un pointeur nu ?
    Le traitement sur le déréférencement peut être adapté à tes besoins, plutôt que faire des choses étranges. Tu peux décider de ne contrôler que les pointeurs NULL, ce qui est déjà une avancée par rapport à ne rien faire du tout.
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  9. #9
    screetch
    Invité(e)
    Par défaut
    Non mon pointeur weak ne fonctionne pas comme celui de boost.
    et le seul interet du pointeur weak, c'est de prévenir lorsque l'objet meurt.
    On donne donc une sorte de garantie, que quelque part, ailleurs, cet objet est vivant, et qu'on peut y accéder. C'est ca qui est bien, dés que j'ai un weak pointeur au lieu d'un pointeur nu, je sais que mon objet est vivant, même si ce n'est pas moi qui le tient en vie.

    Et sinon je l'utilise comme un pointeur nu, mais avec cette sécurité en plus.
    En mode release, c'est comme un pointeur nu en revanche.

    et je suis (heureusement ou malheureusement) en environnement multithread, basé sur un système de jobs. pas trop de garantie sur ce qui tourne au même moment.

Discussions similaires

  1. Diffusion de message dans un graphe d'objet RMI
    Par ultimaroms dans le forum Développement Web en Java
    Réponses: 3
    Dernier message: 28/03/2012, 11h10
  2. [RIA Services] Graphes d'objets et includes
    Par anthyme dans le forum Silverlight
    Réponses: 0
    Dernier message: 14/06/2011, 00h35
  3. Graphe sémantique : objets sémantiques (RFC3)
    Par onjanirina dans le forum Conception (Générale)
    Réponses: 5
    Dernier message: 19/03/2011, 13h17
  4. Charger un graphe d'objets
    Par RogerXXX dans le forum Hibernate
    Réponses: 11
    Dernier message: 15/10/2007, 19h29
  5. [Architecture / Services] Graphe d'objets à sauvegarder
    Par mauvais_karma dans le forum Plateformes (Java EE, Jakarta EE, Spring) et Serveurs
    Réponses: 5
    Dernier message: 05/03/2006, 17h07

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