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

Boost C++ Discussion :

shared_ptr Boost : prob affectation


Sujet :

Boost C++

  1. #1
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Par défaut shared_ptr Boost : prob affectation
    Voilà je commence à m'intéresser un peu aux pointeurs intelligents de boost, enfin shared_ptr. Mais je rencontre un petit problème (avec SDL).

    J'ai un structure comme celle-ci (merci fearyourself ^^) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    // Structure contenant toutes les variables globales
    typedef struct VARGlobales
    {
       SDL_Surface * pEcran; // Pointeur vers la fenêtre d'affichage
       boost::shared_ptr <SDL_Surface> pBitmapCB; // Pointeur intelligent 
       SDL_Event event;
    } VARGlobales;
    Premièrement quand je fais
    VARGlobales sParam = {NULL, NULL}; j'ai un message d'erreur alors que j'en ait pas lorsque je cherche qu'à initialiser à NULL le premier pointeur.

    Puis un peu plus loin, j'utilise un autre shared_ptr :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    // Pointeur intelligent vers un objet FenetrageSDL
       boost::shared_ptr <FenetrageSDL> pFenetre (new FenetrageSDL (800, 600, 32));
    De cette façon, pas de problème pour initialiser, toutefois, dès que je veux initialiser le shared_ptr de ma structure :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sParam.pBitmapCB = SDL_LoadBMP ("cb.bmp"); (la fonction SDL_LoadBMP renvoie un pointeur vers un SDL_Surface, ça devrait marcher :/).
    Ben j'ai un message d'erreur.

    Visiblement les shared_ptr n'accepte pas l'initialisation via le =. Et d'après l'opérateur surchargé =, il ne semble prendre que des shared_ptr comme valeur à droite (shared_ptr & operator=(shared_ptr const & r) // never throws).

    Bref comment faire pour initialiser un pointeur intelligent avec = ? Est-il possible de surcharger son propre = ?

    Et d'autre part, est-ce que les pointeurs intelligents sont lourds à utiliser (je ne parle pas au niveau de la clarté du code, de toute façon j'aime pas les typedef, je trouve ça plus clair quand je vois directement boost::shared_ptr), mais je veux parler en terme de performance ?

    Mirci


  2. #2
    Membre chevronné
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2006
    Messages
    366
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2006
    Messages : 366
    Par défaut
    Salut,

    Effectivement tu ne peux pas affecter à un shared_ptr autre chose qu'un autre shared_ptr pour la simple et unique raison que cela est incompatible avec le fonctionnement d'un shared_ptr.

    De manière simplifiée, un shared_ptr contient un pointeur vers une structure du type :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    template<class T> struc refcount {
    T* t; (ton pointeur géré par le shared_ptr);
    int ref_count;
    }
    Quand tu écris :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    shared_ptr<T> a;
    .....
    //plus loin dans le code, b est un autre shared_ptr<T>
    a = b;
    l'opérateur d'affectation recopie le pointeur de la structure précédente de b dans a et incrémente le paramètre ref_count. Lorsqu'un shared_ptr est détruit, il décrémente le paramètre ref_count, si celui-ci atteint 0, t delete t est appelé.

    Maintenant imaginons que tu puisses écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    shared_ptr<T> a;
    ....
    //plus loin
    T* b = new b();
    ....
    //encore plus loin
    a = b
    Le problème est que le shared_ptr va initialiser sa propre structure refcount. SI un autre shared_ptr se voit affecté le même pointeur b, un problème se pose : le paramètre refcount n'a pas la bonne valeur (1 au lieu de 2 pour chaque shared_ptr). Donc si un shared_ptr est détruit, refcount va passer à 0, l'opérateur delete va être appelé sur le pointeur contenu dans les shared_ptr et le shared_ptr restant contiendra un pointeur invalide. Ce qui va justement à l'encontre du concept de shared_ptr.

    J'espère que c'est pas trop mal expliqué (ce serait beaucoup plus simple avec un schéma :s) mais en fouillant un peu dans la doc de boost tu devrais trouver des explications un peu plus détaillées sur l'implémentation des shared_ptr.

    Pour ce qui est de la lourdeur, par rapport à un pointeur normal, un shared_ptr rajoute une copie : celle d'un int (le paramètre ref_count). Donc non ce n'est pas lourd à utiliser, à moins que tu aies vraiment de très grosses contraintes de performance.

    Pour ton problème, la solution la plus simple consiste à encapsuler ton appele de fonction dans un shared_ptr tu ne devrais plus avoir de soucis.

    Enfin pour l'initialisation avec {Nulln Null}, dis toi que même si un shared_ptr à la sémantique d'un pointeur, cela reste un objet. Il est donc aussi illégal d'écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    shared_ptr<T> a;
    //plus loin
    a = 0;
    que d'écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    Object a;
    //plus loin
    a = 0
    Voilà en espérant t'avoir aidé :p

  3. #3
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Par défaut
    Ok merci beaucoup de la réponse. C'est très clair.

    Sinon, il n'y a donc aucune possibilité - à peu près propre - d'utiliser les pointeurs intelligents tout en pouvant faire ce que je souhaite ? :/

    J'avais pensé à faire une petite classe ptrSmart du style

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template <typename T>
    class ptrSmart
    {
    public:
       ptrSmart ();
       ~ptrSmart ();
       T * operator= (const T &);
       private:
    boost::shared_ptr <T> ptr;
    }
    Et là je pourrai surchargé l'opérateur=.

    Désolé pour le code il y a sûrement des fautes au niveau des templates sur la surcharge de =, mais là faut que j'aille voir le futchbol, pas le temps de réflechir si c'est correct, mais je pense que vous saississez l'idée.

    Mais bon après ce serait vraiment très contraignant à mettre en place tout ça pour le peu d'avantage que j'y gagnerai...

  4. #4
    Membre chevronné
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2006
    Messages
    366
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2006
    Messages : 366
    Par défaut
    Pourquoi ne pas simplement encapsuler ton appel de fonction dans un nouveau shared_ptr ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    sParam.pBitmapCB = shared_ptr<SDL_Surface>(SDL_LoadBMP ("cb.bmp"));
    D'une part cela est plus simple, d'autre part, si tu écris ta propre structure encapsulant un shared_ptr, l'implémentation de ton opérateur = surchargé sera forcé de faire d'affecter au shared_ptr de ta structure un autre shared_ptr.

  5. #5
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Par défaut
    Ah ouais mais là ça va devenir vachement bien complexe à écrire pour le seul bénéfice de ne pas avoir de delete à faire. Je vais me tâter parceque c'est vrai que ça a l'avantage de ne plus avoir de delete à faire (ni d'oubli, plus rien à se préocupper), mais en même temps ça complique vachement le code...

    Tu conseillerais quoi toi ? Si ça peut être décisif, ce sera pour des jeux vidéo (quand j'aurais reçu mon bouquin OpenGL ne tout cas )

  6. #6
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Par défaut
    Si tu commences à encapsuler l'encapsuleur, on n'en finira pas
    Si les pointeurs intelligents de Boost ont cette interface, c'est pour une raison, et elle t'a été donnée. De même, le pointeur intelligent de la bibliothèque standard a le même "inconvénient".
    Ca t'oblige simplement à faire plus attention, c'est pas grave, ça ne coûte rien d'être plus attentif, au contraire.

    Pour ta première question, c'est normal que ça ne marche pas, cette écriture est héritée du C et ne fonctionne qu'avec des valeurs, ça ne peut pas marcher avec des classes qui ont des constructeurs - et une fois de plus, ce n'est pas plus mal

  7. #7
    Membre chevronné
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2006
    Messages
    366
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2006
    Messages : 366
    Par défaut
    Question pas évidente :p

    En fait cela dépend beaucoup de la manière dont tu vas coder ton jeu. Si tu te fais un gestionnaire de ressources, alors tous les objets gérés par ce gestionnaire de ressource pourront être manipulés via des pointeurs classiques, le gestionnaire se chargeant de la durée de vie de tes objets (et encore il aura peut-être parfois d'aide, cela va dépendre de la manière dont tu le codes). De même pour les objets qui ont une durée de vie lié à un autre, ceux-ci n'ont pas vraiment besoin d'être gérés via des shared_ptr, l'objet les contenant se chargeant de les détruire ; idem pour les objets ayant une durée de vie facile à prédéterminer.

    Disons que perso j'utilise les shared_ptr pour les ressources partagées seulement, autrement dit quand plusieurs objets utilisent de manière indépendante le même objet et que je ne sais pas lequel le libèrera en dernier. Un exemple plus concret est assez typique de l'utilisation des shared_ptr est celui de messages à broadcaster. Ne sachant pas si les récepteurs sont tous disponibles, le message va être mis dans des files d'attente (une par récepteur) ; pour des raisons diverses (éviter une copie d'un gros message, polymorphisme ou autre), ce message est passé par pointeur. Les récepteurs viennent le chercher quand ils sont dispos, le message est détruit lorsque le dernier récepteur l'a récupéré. Les shared_ptr évitent de nombreux tests ainsi que pas mal de dépendances inutiles entre les différentes files.

    Voilà c'est un sujet qui mériterait un long débat à lui tout seul, désolé si ma réponse est évasive, mais comme je l'ai dit cela dépend beaucoup de ce que tu veux faire, et aussi de tes préférences 5jusqu'à quel point la gestion de la mémoire dynamique personnelle est préférable à l'écriture de code plus lourd, etc ...).

  8. #8
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Par défaut
    Merci à tous, j'ai tout lu avec attention (j'ai relu le coup du refcount, c'est si j'ai bien compris c'est une variable static qui est partagé entre tous les shared_ptr et qui est incrémenté à chaque nouvel objet et décrémenter dès qu'un objet est détruit c'est bien ça ?). En tout cas ça me réduit pas mal mes utilisations que je pourrais faire, mais c'est vrai que dans ce que je souhaite faire (plusieurs ressources, bitmaps,...), il est quand même pas très long de faire des delete dessus. Mais le problème c'est que j'oublie toujours que les shared_ptr sont des objets, je me trompe souvent ^^.

    Je met le tag résolu .

  9. #9
    Membre chevronné
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2006
    Messages
    366
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2006
    Messages : 366
    Par défaut
    Juste une petite precision, le refcount n'est pas une variable statique, mais une variable partagee entre les differentes copies d'un shared_ptr.

  10. #10
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Par défaut
    Euh,... quand j'utilises une variable static dans une classe c'est justement pour avoir une variable partagée entre tous les objets ^^. Quelle est la différence (désolé de poser autant de question débile, j'aime bien comprendre ^^) ?

  11. #11
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Le refcount n'est pas partagé entre tous les shared_ptr du programme, seulement entre ceux qui pointent sur le même objet.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

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

Discussions similaires

  1. Copie de boost::shared_ptr
    Par Kurisu dans le forum Boost
    Réponses: 2
    Dernier message: 07/09/2006, 15h29
  2. [BOOST] shared_ptr et void*
    Par bourrik dans le forum Bibliothèques
    Réponses: 16
    Dernier message: 16/06/2006, 17h12
  3. boost::shared_ptr et singletons
    Par Elendil_BzH dans le forum Bibliothèques
    Réponses: 2
    Dernier message: 15/01/2006, 20h45
  4. Prob chemins des includes de la lib boost
    Par onap dans le forum C++Builder
    Réponses: 2
    Dernier message: 13/05/2005, 11h56
  5. [BOOST] shared_ptr et pointer C
    Par zdra dans le forum Bibliothèques
    Réponses: 7
    Dernier message: 08/05/2005, 14h15

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