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

Langage C++ Discussion :

Autour de shared_ptr


Sujet :

Langage C++

  1. #1
    Membre très actif
    Homme Profil pro
    Second de cuisine
    Inscrit en
    Avril 2005
    Messages
    193
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Second de cuisine
    Secteur : Alimentation

    Informations forums :
    Inscription : Avril 2005
    Messages : 193
    Par défaut Autour de shared_ptr
    Bonjour,

    J'aimerais realiser un chargement/dechargement dynamique de ma memoire autour d'une classe X, cette classe étant gerée par la classe Y, qui transformera l'objet X, en une std::map<A, X*>, ou std::map<A, shared_ptr<X>>.

    Le but, étant d'utiliser le compteur interne au shared_ptr, et dès qu'il touche 0, l'objet de type X sera decharge de la memoire !

    En gros, la classe Y ressemblerait à ceci:
    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
    template<class C, typename T>
    class shared_structure
    {
    public:
        class does_not_exist
        {
        public:
            does_not_exist() {}
            virtual ~does_not_exist() throw() {}
        };
        class not_loaded
        {
        public:
            not_loaded() {}
            virtual ~not_loaded() throw() {}
        };
        shared_structure() { }
        virtual ~shared_structure() {}
        std::shared_ptr<C> get() { return std::make_shared(this); }
        typedef typename std::map<T, std::shared_ptr<C>>& gets_t;
        typedef typename std::pair<const T, std::shared_ptr<C>>& gets_single_t;
        typedef typename std::map<T, std::shared_ptr<C>>::iterator gets_iterator_t;
        static inline gets_t gets() { return structures; }
        static void clear() { structures.clear(); }
        static typename std::map<T, std::shared_ptr<C>>::iterator begin() { return std::begin(structures); }
        static typename std::map<T, std::shared_ptr<C>>::iterator end() { return std::end(structures); }
        std::size_t get_count() const { return use_count(); }
    protected:
        static std::map<T, std::shared_ptr<C>> structures;
    };
    Avec ceci, je peux donc faire...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    class X;
    class X: public shared_structure<type_clé, X> {};
    Est-ce une bonne façon de faire ?
    Comment detecter le compteur touchant 0 et liberer le pointeur ?

    Merci, nico

  2. #2
    Membre Expert Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 048
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 048
    Par défaut
    Comment detecter le compteur touchant 0 et liberer le pointeur ?
    Le but du shared_ptr est que le contenu est delete si le shared_ptr<> est détruit et que son conteur est à 1. Sinon il y a un reset je crois mais je sais pas si il le delete

  3. #3
    Membre actif
    Homme Profil pro
    Ingénieur
    Inscrit en
    Octobre 2006
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Transports

    Informations forums :
    Inscription : Octobre 2006
    Messages : 48
    Par défaut
    Bonsoir,

    Je partirai sur un pattern Observer. Avant que l'objet soit détruit il notifie l'observateur (l'entité maintenant la map).

    J'éviterai de toucher à la mécanique de shared_ptr.

  4. #4
    Membre Expert Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 048
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 048
    Par défaut
    Si tu utilises un obeserveur pourquoi utiliser les shared_ptr?

    dans la doc du shared_ptr je vois :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template< class Y, class Deleter > 
    shared_ptr( Y* ptr, Deleter d );
    Spécifies ton propre deleter qui va supprimer dans la map si tu en a plus besoin

    exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    void Deleter( T* ptr)
    {
            map->delete(this);
            delete ptr;
    }
    ou un truc du genre.

  5. #5
    Membre actif
    Homme Profil pro
    Ingénieur
    Inscrit en
    Octobre 2006
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Transports

    Informations forums :
    Inscription : Octobre 2006
    Messages : 48
    Par défaut
    +1 Pas besoin d'un observateur. Le cas d'utilisation est prévu par shared_ptr... map->delete(this); ?

  6. #6
    Membre très actif
    Homme Profil pro
    Second de cuisine
    Inscrit en
    Avril 2005
    Messages
    193
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Second de cuisine
    Secteur : Alimentation

    Informations forums :
    Inscription : Avril 2005
    Messages : 193
    Par défaut
    Bon je vais poster un exemple précis de ce que j'utilises en ce moment :
    Voici la classe qui hérite de shared_structure:

    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
     
    namespace dbs
    {
    class Server;
    class Server: public shared_structure<Server, std::string>
    {
    public:
        Server() :
            shared_structure<Server, std::string>()
            /// variables
            {}
        virtual ~Server() { }
        static Server& load(soci::session& sql, const std::string& linkname);
        static Server& load_sql(soci::session& sql, const std::string& linkname);
    };
    }
    La fonction load testera l'existance de linkname dans la map (shared_structure::map<C, T>)

    Et voici le problème:
    Juste avant, j'avais mis un compteur , plus un pointeur nu, pour avoir le nombre d'instances:
    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
     
    int main()
    {
        soci::session& sql(dbs::Driver::instance().getSession());
        dbs::Server& One(dbs::Server::load(sql, "MasterServer"));
        std::cout << "One = " << One.get_count() << std::endl;
        dbs::Server& Two(dbs::Server::load(sql, "MasterServer"));
        std::cout << "One = " << One.get_count() << " ; Two = " << Two.get_count() << std::endl;
        if(true)
        {
            dbs::Server& Three(dbs::Server::load(sql, "MasterServer"));
            std::cout << "One = " << One.get_count() << " ; Two = " << Two.get_count() << " ; Three = " << Three.get_count() << std::endl;
        }
        std::cout << "One = " << One.get_count() << " ; Two = " << Two.get_count() << std::endl;
        return 0;
    }
    Le résultat étant:
    One = 1
    One = 2 ; Two = 2
    One = 3 ; Two = 3 ; Three = 3
    One = 3 ; Two = 3
    La decrementation ne se faisant pas, c'est donc pas ce que je souhaite !
    Donc quelle solution choisir ?
    merci, nico

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 635
    Par défaut
    Salut,

    Peut etre devrais tu déjà commencer par te poser la question de savoir si la propriété de tes pointeurs est bel et bien partagée.

    En effet, tu as peut etre plusieurs utilisateurs de ton pointeur mais un seul propriétaire responsable de la durée de vie

    Si tel est le cas, tu peux parfaitement utiliser un unique_ptr dans la collection et un pointeur nu au niveau des utilisateurs.

    Il faudra cependant envisager un autre moyen pour arriver à déterminer "le meilleur moment" pour supprimer ton unique_ptr de ta collection

    Au niveau du shared_ptr, tu peux toujours envisager de baser ta politique de retrait de ta collection sur le résultat de la fonction unique() qui indique, justement, si l'objet est utilisé "par ailleurs"

    NOTA: les fonctions reset detruisent d'office la ressource d'origine, qu'il y ait remplacement par une autre ressource ou non, autrement il y aurait une fuite mémoire. Mais, s'il n'y a pas remplacement de la ressource, cela ne fait que placer le shared_/unique_ptr dans un état invalide (get() renverra nullptr), sans provoquer la destruction de celui-ci, et sans provoquer le retrait du pointeur intelligent de la collection dans laquelle il se trouve (comment pourrait-il le faire )

    Il ne faut donc pas toucher au mécanisme interne des shared_/unique_ptr, mais tu disposes de plusieurs solutions pour déterminer si la ressource manipulée par le pointeur intelligent est encore disponible ou non, et donc pour baser une politique de retrait sur base de cette information
    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

  8. #8
    Membre très actif
    Homme Profil pro
    Second de cuisine
    Inscrit en
    Avril 2005
    Messages
    193
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Second de cuisine
    Secteur : Alimentation

    Informations forums :
    Inscription : Avril 2005
    Messages : 193
    Par défaut
    Bon he bien apparement cette definition de classe semble me convenir

    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
    32
    33
    34
    35
    36
    37
    38
    39
     
    template<class C, typename T>
    class shared_structure
    {
    public:
        typedef typename std::shared_ptr<C> ptr;
        typedef typename std::map<T, ptr> map_t;
        typedef typename std::pair<const T, ptr> pair_t;
        typedef typename std::map<T, ptr>::iterator iterator_t;
        class does_not_exist
        {
        public:
            does_not_exist() {}
            virtual ~does_not_exist() throw() {}
        };
        class not_loaded
        {
        public:
            not_loaded() {}
            virtual ~not_loaded() throw() {}
        };
        shared_structure(const T& key) {
            auto sptr = std::shared_ptr<C>(reinterpret_cast<C*>(this));
            structures.insert({key, sptr});
        }
        virtual ~shared_structure() { }
        static void clear() { structures.clear(); }
        static const map_t& get() { return structures; }
        static ptr get_ptr(const T& key) { return structures.at(key); }
        static std::string table_name;
    protected:
        static map_t structures;
        static T find_id(soci::session& sql, const std::string& arg)
        {
            T id = 0;
            sql << "SELECT id FROM `" << T::table_name << "` WHERE `name`='" << arg << "'`", soci::into(id);
            return id;
        }
    };
    Merci

  9. #9
    Membre Expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Par défaut
    Je n'ai pas tout compris a ta question mais il y a des points qui me semble bizarre.

    Alors je vais juste te donner des conseils pour ce genre de design de system:

    1. Hevite l'heritage autant que tu peux.
    2. Separe toujours totalement la fonctionalite (la classe) de la gestion du temps de vie de la dite fonctionalite.

    Le second point implique:

    1. Le temps de vie d'un objet du type que tu design ne dois pas etre visible sur la declaration de la classe. Ce qui doit etre visible c'est si on peut ou pas copier l'objet, ou le deplacer ou pas.
    2. Si les objets de ce type doivent absolument etre gere par exemple via un shared_ptr, fais juste en sorte qu'il y ait une factory qui fournis ce shared_ptr.
    3. Si un type doit gerer les instances d'un autre type via des shared_ptr, qu'il le fasse sans que ca se voit dans la declaration (hors fonctions d'ajout ou declaration de conteneurs).

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

Discussions similaires

  1. tourner autour d'1 objet ds ttes les directions
    Par Mat 74 dans le forum OpenGL
    Réponses: 2
    Dernier message: 20/10/2004, 20h48
  2. Tourner autour d'un polygône
    Par DeathMaker dans le forum OpenGL
    Réponses: 6
    Dernier message: 12/10/2004, 10h30
  3. Tourner autour d'une scéne
    Par apdsi dans le forum OpenGL
    Réponses: 3
    Dernier message: 19/08/2004, 12h53
  4. Dessiner un cadre autour des composants
    Par Pill_S dans le forum Composants
    Réponses: 5
    Dernier message: 03/07/2004, 14h08
  5. Rotation d'un rectangle autour du centre de gravité
    Par bucheron dans le forum Algorithmes et structures de données
    Réponses: 13
    Dernier message: 22/06/2004, 11h01

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