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 :

[template] un smart pointer parmi d'autres


Sujet :

C++

  1. #21
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Il contient 2 pointeurs, là où celui de boost n'en contient qu'un, qui pointe vers une structure avec ref count et pointeur.
    Je viens de regarder le code de shared_ptr (ou weak_ptr), et il me semble que tu te trompes. Il y a un pointeur ET une class shared_count (ou weak_count) qui contient elle-même au moins un pointeur. Cela fait au moins deux pointeurs. Pas mieux donc...
    Par contre ce que tu décris (un pointeur vers une structure avec un pointeur et un compteur) ressemble très fort au premier smart pointer dont je parle au tout début de cette discussion. Et, justement, Médinoc soulevait que cela ajoutait une indirection supplémentaire (point 5), bien qu'en admettant que son avantage soit d'être (le) plus léger (possible).
    Parmi les deux smart pointers de cette discussion, le premier est le plus léger, le deuxième le plus performant (enfin, tant qu'on ne s'amuse pas à en faire des dizaines de copies, car le detach() peut être très lourd... Il suffirait alors d'avoir une liste bidirectionelle, mais cela nous ferait 3 pointeurs)
    Citation Envoyé par JolyLoic Voir le message
    Peut-être est-ce plus détaillé là : http://loic-joly.developpez.com/tuto...inters/#LIII-B
    OK, je vois. La discussion est intéressante. Mais il y a des moments où, à force d'essayer de combler les "lacunes" du C++ afin de prévoir tous les cas possibles qui en ferait un langage aussi "facile" et "robuste" à utiliser qu'un Java ou autre C#, autant utiliser ces derniers... Un bon programmeur C++ n'est pas celui qui utilise le moins de delete possible, mais celui qui sait pourquoi il l'utilise. La robustesse est mieux garantie par l'expérience que par un outil ou un langage.
    Mais bon, là on sort de la discussion simplement technique pour entrer dans une discussion idéologique.

  2. #22
    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 : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

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

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    Citation Envoyé par camboui Voir le message
    Ce code est trouvé en interne. Je suis preneur de tout autre code qui se resume à un simple fichier header à inclure. Les usines à gaz me seront refusées (je ne décide pas).
    Tu prends l'en-tête shared_ptr et voilà.

    De plus, les compilateurs tendent à proposer maintenant une implémentation de TR1, donc si tu as compilo récent qui le propose, fonce, si tu peux rester à jour, au moment où tu auras une implémentation de TR1, tu changes shared_ptr par le nouveau.

    Et ne pas vouloir Boost alors qu'il est en standard sous Linux, c'est...

  3. #23
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Citation Envoyé par Matthieu Brucher Voir le message
    Et ne pas vouloir Boost alors qu'il est en standard sous Linux, c'est...
    La prochaine/nouvelle version de BCB fournit Boost, VC++ commence à bien aimer Boost (je parle de l'équipe VC++ de chez MS) en plus de tout cela.

    Boost promet un avenir très correct au C++.

  4. #24
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Allez, un dernier pour la route
    A défaut d'être pratique, puisque vous ne jurez que par du prêt-à-porter (avec raison), l'expérience est didactique, pédagogique.

    Ainsi, comme vous reprochiez aux deux précédents smart pointers de n'être soit pas assez "léger", soit pas assez "direct", je viens d'en concocter un troisième qui ne souffre d'aucun de ces deux défauts (mais peut-être d'un autre...)
    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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    template<class T>
    class detached_auto_counter
    {
    	struct counter_ptr
    	{
    		long s_cnt;
    		T *s_ptr;
    		counter_ptr(T *ptr=NULL)
    			:s_cnt(0l),s_ptr(ptr) {}
    		bool operator<(const counter_ptr & r) const
    			{ return unsigned(s_ptr)<unsigned(r.s_ptr); }
    	};
    	std::set<counter_ptr> f_counterset;
    public:
    	detached_auto_counter()
    		{ Keep(NULL); }
    	~detached_auto_counter()
    		{ Release(NULL); }
    	long Keep(T *ptr)
    	{
    		counter_ptr cp(ptr);
    		std::pair<std::set<counter_ptr>::iterator,bool> p=f_counterset.insert(cp);
    		return ++p.first->s_cnt;
    	}
    	long Release(T *ptr)
    	{
    		counter_ptr cp(ptr);
    		std::set<counter_ptr>::iterator it=f_counterset.find(cp);
    		long r=--it->s_cnt;
    		if (r==0)
    			f_counterset.erase(it);
    		return r;
    	}
    };
     
     
    extern detached_auto_counter<void> g_detached_auto_counter;
     
     
    template<class T>
    class dsmart_ptr
    {
    	T *f_ptr;
    public:
    	explicit dsmart_ptr(T *ptr=NULL)
    		:f_ptr(ptr)
    	{
    		std::auto_ptr<T> ap(ptr);
    		g_detached_auto_counter.Keep(ptr);
    		ap.release();
    	}
    	dsmart_ptr(const dsmart_ptr<T> & r)
    		:f_ptr(r.f_ptr)
    	{
    		g_detached_auto_counter.Keep(f_ptr);
    	}
    	dsmart_ptr<T> & operator=(const dsmart_ptr<T> & r)
    	{
    		T *ptr=r.f_ptr;
    		g_detached_auto_counter.Keep(ptr);
    		if (g_detached_auto_counter.Release(f_ptr)==0)
    			delete f_ptr;
    		f_ptr=ptr;
    		return *this;
    	}
    	~dsmart_ptr()
    	{
    		if (g_detached_auto_counter.Release(f_ptr)==0)
    			delete f_ptr;
    	}
    	operator bool() const
    		{ return f_ptr!=0; }
    	T & operator*() const
    		{ return *f_ptr; }
    	T *operator->() const
    		{ return f_ptr; }
    	T *get() const
    		{ return f_ptr; }
    };
    Le défaut ? Il faut déclarer une variable globale (g_detached_auto_counter). C'est elle qui s'occupe du comptage de référence en lieu et place du smart pointer lui-même. Mais est-ce vraiment un problème ?

    Sinon, à vos commentaires

    En fait je voudrais que vous m'aidiez à une chose: le multi-threading. Je suis assez novice en la matière. Supposez qu'il ne faille que vérouiller Keep() et Release() (ou Attach() et Detach() dans le précédant smart pointer), comment faire concrètement ? (sous Win32).
    Merci.

    Après je vous fiche la paix, promis

  5. #25
    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 : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

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

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    Citation Envoyé par camboui Voir le message
    Le défaut ? Il faut déclarer une variable globale (g_detached_auto_counter). C'est elle qui s'occupe du comptage de référence en lieu et place du smart pointer lui-même. Mais est-ce vraiment un problème ?

    Sinon, à vous commentaires

    En fait je voudrais que vous m'aidiez à une chose: le multi-threading. Je suis assez novice en la matière. Supposez qu'il ne faille que vérouiller Keep() et Realse() (ou Attach() et Detach() dans le précédant smart pointer), comment faire concrètement ? (sous Win32).
    Une variable globale en multi-thread -> poubelle.

    Sincèrement, prend le pointeur de Boost, tu n'es pas obligé de tout prendre, mais 3-4 en-têtes, c'est pas la mort, surtout que c'est testé robuste, ... tandis que le tien a des défauts de jeunesse qui peuvent être fatals.

  6. #26
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Citation Envoyé par Matthieu Brucher Voir le message
    Une variable globale en multi-thread -> poubelle.
    Tu as des arguments, une doc ou un tuto sur le sujet ?


    Sinon, j'ai pris mon courage à deux mains et j'ai pris une bonne centaine de headers de boost pour essayer ce fameux boost::shared_ptr (un peu plus que 3-4 headers donc...). Un simple petit #include, deux-trois instances et... ça marche du premier coup avec VC++6 ! Je ne l'aurais jamais cru
    Ça m'a permis de voir d'un peu plus près ce qu'il en est en débuggant son code. Le premier smart pointer de cette discussion lui ressemble très fort finalement. Il suffirait de dédoubler le pointeur de auto_ptr dans la classe smart_ptr afin d'éviter la double indirection (point 5 de Médinoc) pour retrouver un fonctionnement très proche de celui de boost::shared_ptr.
    Par contre, la présence de boost::weak_ptr est un boulet... Sa gestion ajoute lourdeur et perte de performance quand on en a pas besoin. Il devrait y avoir un autre smart pointer en plus genre boost::lite_shared_ptr, sans weak_ptr associé donc.
    Pour finir, lors du comptage et décomptage de référence, les fonctions InterlockedIncrement et InterlockedDecrement sont systématiquement appelées aussi en single-thread, ce qui est inutile.

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Pour le problème du strong/weak, j'ai vu trois cas de figures:
    1. strong uniquement -> ton lite_shared_ptr
    2. strong et weak, impossible d'obtenir une strong à partir d'une weak -> Je ne sais même pas si ça a une quelconque utilité, mais je peux faire ça sans section critique, avec juste du InterlockedIncrement/Decrement.
    3. strong et weak, possibilité d'upgrader une weak en strong -> Je ne sais pas le faire sans une section critique, d'où impact sur les performances.
    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.

  8. #28
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Après une semaine de retournement de smart pointers dans tous les sens, je constate que leur principale difficulté est qu'il faut conserver quelque part un moyen pour savoir si le pointeur à partager est toujours en cours d'utilisation ou pas.

    Le premier smart pointer présenté dans cette discussion, ainsi que celui de boost::shared_ptr, fait toujours une (petite) allocation implicite de mémoire pour y mettre un compteur de référence. Sachant que le pointeur que l'on veut partager est lui aussi résultant d'une allocation de mémoire, cela nous fait toujours deux allocations parallèles de mémoire. C'est une de trop à mon goût.

    Le deuxième smart pointer ne fait pas cette allocation implicite de mémoire. En fait il est autonome, simple et même léger en regard du précédant, même en lui ajoutant un membre qui permettrait de gérer la gestion des références multiples via une liste bidirectionnelle (et cela le rendrait définitivement performant).

    Le troisième smart pointer est du même genre que les deux premiers, sauf que le compteur de référence est géré par une variable globale. Je n'aime pas trop les variables globales, surtout en C++, car on ne sait pas quand elles sont construites. Ainsi, si une autre variable globale utilise ce smart pointer, est-ce que le compteur de référence est déjà construit ?

    Finalement, je me demande si le meilleur smart pointer n'est pas CComPtr, du moins son principe de comptage de référence. Toute classe dont on veut partager une instance avec ce smart pointer doit intégrer son propre compteur de référence. Simple et efficace. Il faut juste compléter toutes les classes existantes si on ne l'a pas prévu dès le départ (réécrire leur code quoi ).

  9. #29
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    À part le coup de la variable globale que je trouve complètement idiot parce que je n'ai toujours pas compris comment tu peux référencer deux objets différents avec ça, le reste de ton post est intelligent.

    C'est là toute la différence entre comptage de références intrusif et non-intrusif. Et, ayant été formé au comptage par COM, je préfère le comptage intrusif.
    L'équivalent existe dans Boost: Il s'agit de la classe boost::intrusive_ptr<>, et des fonctions globales associées.
    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.

  10. #30
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    À part le coup de la variable globale que je trouve complètement idiot parce que je n'ai toujours pas compris comment tu peux référencer deux objets différents avec ça, le reste de ton post est intelligent.
    Heureusement que tu précises que tu n'as pas compris
    La variable globale est en fait une instance d'une classe qui englobe TOUS les compteurs de référence. Ils sont classés dans un arbre (std::set) dont la clé est le pointeur lui-même (considéré comme une simple valeur unsigned).
    Regarde la déclaration "template<class T> class detached_auto_counter" de près, elle est quand même fort simple. En réalité elle n'a pas besoin d'être un template, on peut remplacer "T" par "void" sans plus.
    Et puis, essaye, tu verras que ça fonctionne très bien.
    Tout le code que j'ai posté dans cette discussion a été testé avec ton bout de code UneClasse, entre autres

    Cependant je n'utiliserai pas ce smart pointer. C'était surtout un exercice pour faire le tour des possibilités de gestion d'instances multiples de pointeur.

  11. #31
    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
    Citation Envoyé par camboui Voir le message
    Le premier smart pointer présenté dans cette discussion, ainsi que celui de boost::shared_ptr, fait toujours une (petite) allocation implicite de mémoire pour y mettre un compteur de référence. Sachant que le pointeur que l'on veut partager est lui aussi résultant d'une allocation de mémoire, cela nous fait toujours deux allocations parallèles de mémoire. C'est une de trop à mon goût.
    Il est possible de rassembler les deux, et donc de gagner sur ce coût. C'est ce que fait la fonction make_shared (il faut une version assez récente de boost). C'est aussi ce qui fait que les pointeurs intrusifs ne feront pas partie du C++0x, contrairement aux shared_ptrs : Ils ne sont pas nécessaires.
    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.

  12. #32
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Et bien ! Heureusement que tu m'apprends ça, merci !

    J'étais déjà en train de réfléchir à résoudre l'épineux problème consistant à gérer, en appel de fonction, la quantité variable d'arguments de new T(). A part un soutien du compilateur, je ne voyais pas trop comment faire d'autre qu'en utilisant une macro C. Un petit coup d'oeil rapide au code de make_shared.hpp, et voilà ! Tu m'auras fait gagner du temps
    Donc soit le compilateur accepte les templates à arguments variables (et manifestement ça existe !), soit on écrit autant de templates que nécessaire pour le nombre souhaité de paramètres à passer à new T().
    Merci !

  13. #33
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    shared_ptr + make_shared ça a quand même un overhead par rapport à un shared_ptr qui ne pourrait être construit que d'après un objet ou une factory.
    Boost ftw

  14. #34
    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
    Tu pourrais préciser à quel overhead tu fais allusion ?

    Merci
    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.

  15. #35
    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 : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

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

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    Citation Envoyé par camboui Voir le message
    Le deuxième smart pointer ne fait pas cette allocation implicite de mémoire. En fait il est autonome, simple et même léger en regard du précédant, même en lui ajoutant un membre qui permettrait de gérer la gestion des références multiples via une liste bidirectionnelle (et cela le rendrait définitivement performant).
    Ce qui permet de faire pleins d'allocations dynamiques... Faut savoir ce que tu cherches

    Si tu veux du comptage intrusif, va regarder le pointeur intrusif de Boost.

  16. #36
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    Utilisation mémoire et déréférencements.
    Boost ftw

  17. #37
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Citation Envoyé par Matthieu Brucher Voir le message
    Ce qui permet de faire pleins d'allocations dynamiques... Faut savoir ce que tu cherches
    J'ai parfois l'impression de parler dans le vide, vous ne regardez pas de près le code que je propose.
    Revoici donc le code du 2ème smart pointer proposé, avec liste circulaire doublement liée. Il n'y a ni allocation dynamique ni comptage (intrusif ou pas).
    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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    template<class T>
    class c2smart_ptr
    {
    	T *f_ptr;
    	c2smart_ptr<T> *f_ap,*f_apr;
    	void Attach(const c2smart_ptr<T> & r)
    	{
    		f_apr=(f_ap=r.f_ap)->f_apr;
    		f_ap->f_apr=f_apr->f_ap=this;
    	}
    	void Detach()
    	{
    		f_ap->f_apr=f_apr;
    		f_apr->f_ap=f_ap;
    	}
    public:
    	c2smart_ptr()
    		:f_ptr(0) {f_ap=f_apr=this;}
    	explicit c2smart_ptr(T *ptr)
    		:f_ptr(ptr) {f_ap=f_apr=this;}
    	c2smart_ptr(const c2smart_ptr<T> & r)
    		:f_ptr(r.f_ptr) { Attach(r); }
    	c2smart_ptr<T> & operator=(const c2smart_ptr<T> & r)
    	{
    		if (&r!=this)
    		{
    			c2smart_ptr<T> t(*this); //keep this line !
    			Detach();
    			f_ptr=r.f_ptr;
    			Attach(r);
    		}
    		return *this;
    	}
    	~c2smart_ptr()
    	{
    		if (f_ap==this)
    			delete f_ptr;
    		else
    			Detach();
    	}
    	operator bool() const
    		{ return f_ptr!=0; }
    	T & operator*() const
    		{ return *f_ptr; }
    	T *operator->() const
    		{ return f_ptr; }
    	T *get() const
    		{ return f_ptr; }
    };

  18. #38
    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 : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

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

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    Effectivement, mea culpa, pas d'allocation dynamique. En revanche, il y a un comptage implicite grâce à la liste chaînée.
    A toi de voir si tu as besoin de connaître les références à ton objet pour une raison ou une autre. Mais le design me semble plus fragile (car l'objet est plus complexe puisqu'il effectue plus) qu'un pointeur intelligent avec comptauer explicite.

  19. #39
    Membre éprouvé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Points : 937
    Points
    937
    Par défaut
    Il y a un petit soucis que vous n'avez pas soulevé dans ces smart pointer, le voici:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    smart_ptr<UneClasse> p0(new UneClasse(5));
    smart_ptr<UneClasseDerivee> p0d(new UneClasseDerivee(6));
    p0=p0d;//<-erreur compilateur
    Ils ne sont pas polymorphiques...

    Revoici corrigée la classe c2smart_ptr proposée deux posts plus haut
    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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    template<class T>
    class c2smart_ptr
    {
    	T *f_ptr;
    	c2smart_ptr<T> *f_ap,*f_apr;
    	void Attach(const c2smart_ptr<T> *p)
    	{
    		f_apr=(f_ap=p->f_ap)->f_apr;
    		f_ap->f_apr=f_apr->f_ap=this;
    	}
    	void Detach()
    	{
    		f_ap->f_apr=f_apr;
    		f_apr->f_ap=f_ap;
    	}
    public:
    	c2smart_ptr()
    		:f_ptr(0) {f_ap=f_apr=this;}
    	explicit c2smart_ptr(T *ptr)
    		:f_ptr(ptr) {f_ap=f_apr=this;}
    	template<class Y>
    	c2smart_ptr(const c2smart_ptr<Y> & r)
    		:f_ptr(r.get()) { Attach(reinterpret_cast<const c2smart_ptr<T> *>(&r)); }
    	c2smart_ptr(const c2smart_ptr<T> & r)
    		:f_ptr(r.f_ptr) { Attach(&r); }
    	c2smart_ptr<T> & operator=(const c2smart_ptr<T> & r)
    	{
    		if (&r!=this)
    		{
    			c2smart_ptr<T> t(*this); //keep this line !
    			Detach();
    			f_ptr=r.f_ptr;
    			Attach(&r);
    		}
    		return *this;
    	}
    	~c2smart_ptr()
    	{
    		if (f_ap==this)
    			delete f_ptr;
    		else
    			Detach();
    	}
    	operator bool() const
    		{ return f_ptr!=0; }
    	T & operator*() const
    		{ return *f_ptr; }
    	T *operator->() const
    		{ return f_ptr; }
    	T *get() const
    		{ return f_ptr; }
    };
    Je pense qu'il n'en faut pas plus, sauf que les destructeurs de la hiérarchie de classe qui sera instanciée et conservée dans les smart pointer doivent être "virtual" (mais c'est une régle générale en C++ il me semble).

  20. #40
    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 : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

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

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    shared_ptr a la possibilité de faire ça (cf mon tutoriel, il me semble).

Discussions similaires

  1. Template, Smart Pointer et Valeur par défaut
    Par oxyde356 dans le forum Langage
    Réponses: 10
    Dernier message: 22/03/2011, 23h08
  2. Réponses: 23
    Dernier message: 05/01/2006, 20h15
  3. Smart Pointer
    Par Fry dans le forum C++
    Réponses: 5
    Dernier message: 03/10/2005, 23h13
  4. Utilisation des smart pointer
    Par 0xYg3n3 dans le forum MFC
    Réponses: 11
    Dernier message: 22/04/2005, 18h37
  5. templates et smart pointers
    Par delire8 dans le forum C++
    Réponses: 9
    Dernier message: 10/07/2003, 16h26

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