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

  1. #1
    Membre à l'essai
    Instanciation d'un en-tête "shared_ptr.h" en c++ dans la norme avant la 11
    Bonjour,

    Je souhaite connaître la manière d'instancier avant la norme 11 en c++ un en-tête shared_ptr.h (ci-dessous) dans un fichier .cpp de ce type :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    shared_ptr<Personne> p = new Personne(nom)


    En effet, le shared_ptr ne peut être instancié avec le makeshared de la norme 11 du c++.

    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
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    #ifndef SHAREDPTR_H
    #define SHAREDPTR_H
    #include <assert.h>
    namespace ag {
    //--- classe d'exception
    class ref_error {};
     
    //--- modèle du pointeur partagé
    template <typename T>
    class shared_ptr
    {
    		public:
    //--- opérateurs de déréférencement
    		T* operator->() const throw()
    		{
    			assert(ptr_ref!=NULL);
    			return ptr_ref->get();
    		}
    		T& operator*() const throw()
    		{
    			assert(ptr_ref!=NULL);
    			return *(ptr_ref->get());
    		}
    //--- accès à la donnée interne
    		T* get() const throw(){
    			assert(ptr_ref!=NULL);
    			return ptr_ref->get();
    		}
    //--- constructeurs / destructeur
    		shared_ptr(T* p){ptr_ref=new shared_ptr_ref(p);}
    		shared_ptr() throw() :ptr_ref(0){}
    		shared_ptr(const shared_ptr& p) throw()
    		{
    			if(p.ptr_ref)
    				p.ptr_ref->Prend(); // prend la responsabilité de l'objet partagé
    			ptr_ref=p.ptr_ref;
    		}
    		~shared_ptr()
    		{
    			if(ptr_ref)
    				ptr_ref->Libere(); // perd la responsabilité de l'objet partagé
    		}
    //---affectation
    		shared_ptr& operator=(const shared_ptr& p)
    		{
    			if(ptr_ref)
    				ptr_ref->Libere(); // perd une responsabilité sur l'ancien objet
    			if(p.ptr_ref)
    				p.ptr_ref->Prend();// prend une responsabilité sur un nouvel objet
    			ptr_ref=p.ptr_ref;
    			return *this;
    		}
    		shared_ptr& operator=(T* ptr)
    		{
    			if(ptr_ref) ptr_ref->Libere();
    			ptr_ref = new shared_ptr_ref(ptr);
    			return *this;
    		}
     
     
    //--- comparaisons
    		bool operator==(T* ptr) const
    		{
    			bool ok=false;
    			if(ptr_ref==0)
    				ok =(ptr==0);
    			else
    				ok = (ptr_ref->get()==ptr);
    			return ok;
    		}
    		bool operator!=(T* ptr) const {return !operator==(ptr);}
    		operator bool() const
            {
                return (ptr_ref!=0 && ptr_ref->get()!=0);
            }
     
    		private:
    //--- classe assistante représentant l'objet partagé
    		class shared_ptr_ref
    		{
    				T* ptr; // la donnée interne
    				mutable int count; // le comptage de références : mutable car amené à changer même sur un shared_ptr_ref const.
    	// on interdit la copie et l'affectation
    				shared_ptr_ref(const shared_ptr_ref&);
    				void operator=(const shared_ptr_ref&);
     
    				public:
    	// constructeurs / destructeur
    				explicit shared_ptr_ref(T* p) throw() :ptr(p),count(1){}
    				~shared_ptr_ref(){delete ptr;}
    	// gestion des références
    				void Prend() const throw() {++count;}
    				void Libere(){--count; if(count==0) delete this;}
    	// accès à la donnée interne
    				T* get() const throw(){return ptr;}
    		};
    		mutable shared_ptr_ref* ptr_ref; // référence partagée
    };
     
     
    } // fin du namespace
    #endif


    Cette étude me permettra de comprendre de manière basique le fonctionnement des pointeurs intelligents.

    D'avance merci

  2. #2
    Rédacteur/Modérateur

    shared_ptr est arrivé en C++11 en même temps que make_shared.
    Ton shared_ptr là est juste une classe et tu peux litérallement lire les constructeurs et opérateurs d'affectation pour en instancier un objet.
    Donc le problème ou l'erreur est...?
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Membre à l'essai
    Merci Bousk,
    Si je comprend bien, je ne peux pas instancier un objet à l'aide de l'en-tête shared_ptr.h en l'ajoutant avec #include dans un fichier .cpp avant la norme 11 ?
    En effet, je ne souhaite pas forcément utiliser "make_shared" mais une allocation dynamique de type new ou autre.
    En fait, je souhaite avant la norme c++ 11, créer une allocation dynamique à l'aide de ce fichier en-tête. Est-ce possible et comment faire ?
    Merci d'avance

  4. #4
    Expert confirmé
    Tu as donné la réponse dans ta question initiale, il faut utiliser l'opérateur new (mais jamais le delete) :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    shared_ptr<Personne> p = new Personne(nom);

  5. #5
    Membre à l'essai
    Merci dalfab,

    Dans cet exemple en c++ avant la norme 11, le compilateur (Visual Studio 2010) trouve de drôles d'erreurs que je ne saurais résoudre seul :

    personne.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
    #ifndef PERSONNE_H
    #define PERSONNE_H
    #include <string>
     
    class Logement;
     
    class Personne
    {
        std::string identite;
        Logement *residence;
    public:
        Personne(std::string id);
        std::string ToString() const;
        void Emmenage(Logement *l);
     
    };
     
    #endif // PERSONNE_H


    personne.cpp
    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
    #include "personne.h"
    #include "logement.h"
    #include <sstream>
     
    Personne:<img src="images/smilies/icon_razz.gif" border="0" alt="" title=":P" class="inlineimg" />ersonne(std::string id):identite(id),residence(nullptr)
    {
    }
     
    void Personne::Emmenage(Logement *l)
    {
        if(residence!=nullptr)
            residence->Depart(this);
        residence = l;
        if(residence!=nullptr)
            residence->Arrivee(this);
    }
     
    std::string Personne::ToString() const
    {
       std::ostringstream flux;
       flux << identite;
       if(residence!=nullptr)
       {
           flux << " ("<<residence->ToString()<<")";
       }
       return flux.str();
    }


    logement.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
    #ifndef LOGEMENT_H
    #define LOGEMENT_H
    #include <string>
    #include <set>
     
    class Personne;
     
    class Logement
    {
        std::string adresse;
        std::set<Personne*> occupants;
    public:
        Logement(std::string ad);
        std::string ToString() const;
        void Arrivee(Personne* p);
        void Depart(Personne *p);
        std::string ListeOccupants() const;
    };
     
    #endif // LOGEMENT_H


    logement.cpp
    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
    #include "logement.h"
    #include "personne.h"
    #include <sstream>
     
    Logement::Logement(std::string ad):adresse(ad)
    {
    }
     
    std::string Logement::ToString() const
    {
        return adresse;
    }
     
    void Logement::Arrivee(Personne *p)
    {
        occupants.insert(p);
    }
     
    void Logement:<img src="images/smilies/icon_biggrin.gif" border="0" alt="" title=":D" class="inlineimg" />epart(Personne *p)
    {
        occupants.erase(p);
    }
     
    std::string Logement::ListeOccupants() const
    {
        std::ostringstream flux;
    	/*std::set<Personne*> Logement::occupants;*/
        for(std::set<Personne*>::iterator i=occupants.begin();i!=occupants.end();++i)
        {
            flux << (*i)->ToString() << ',';
        }
        return flux.str();
    }


    shared_ptr.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
    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
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    #ifndef SHAREDPTR_H
    #define SHAREDPTR_H
    #include <assert.h>
    namespace ag {
    //--- classe d'exception
    class ref_error {};
     
    //--- modèle du pointeur partagé
    template <typename T>
    class shared_ptr
    {
    		public:
    //--- opérateurs de déréférencement
    		T* operator->() const throw()
    		{
    			assert(ptr_ref!=NULL);
    			return ptr_ref->get();
    		}
    		T& operator*() const throw()
    		{
    			assert(ptr_ref!=NULL);
    			return *(ptr_ref->get());
    		}
    //--- accès à la donnée interne
    		T* get() const throw(){
    			assert(ptr_ref!=NULL);
    			return ptr_ref->get();
    		}
    //--- constructeurs / destructeur
    		shared_ptr(T* p){ptr_ref=new shared_ptr_ref(p);}
    		shared_ptr() throw() :ptr_ref(0){}
    		shared_ptr(const shared_ptr& p) throw()
    		{
    			if(p.ptr_ref)
    				p.ptr_ref->Prend(); // prend la responsabilité de l'objet partagé
    			ptr_ref=p.ptr_ref;
    		}
    		~shared_ptr()
    		{
    			if(ptr_ref)
    				ptr_ref->Libere(); // perd la responsabilité de l'objet partagé
    		}
    //---affectation
    		shared_ptr& operator=(const shared_ptr& p)
    		{
    			if(ptr_ref)
    				ptr_ref->Libere(); // perd une responsabilité sur l'ancien objet
    			if(p.ptr_ref)
    				p.ptr_ref->Prend();// prend une responsabilité sur un nouvel objet
    			ptr_ref=p.ptr_ref;
    			return *this;
    		}
    		shared_ptr& operator=(T* ptr)
    		{
    			if(ptr_ref) ptr_ref->Libere();
    			ptr_ref = new shared_ptr_ref(ptr);
    			return *this;
    		}
     
     
    //--- comparaisons
    		bool operator==(T* ptr) const
    		{
    			bool ok=false;
    			if(ptr_ref==0)
    				ok =(ptr==0);
    			else
    				ok = (ptr_ref->get()==ptr);
    			return ok;
    		}
    		bool operator!=(T* ptr) const {return !operator==(ptr);}
    		operator bool() const
            {
                return (ptr_ref!=0 && ptr_ref->get()!=0);
            }
     
    		private:
    //--- classe assistante représentant l'objet partagé
    		class shared_ptr_ref
    		{
    				T* ptr; // la donnée interne
    				mutable int count; // le comptage de références : mutable car amené à changer même sur un shared_ptr_ref const.
    	// on interdit la copie et l'affectation
    				shared_ptr_ref(const shared_ptr_ref&);
    				void operator=(const shared_ptr_ref&);
     
    				public:
    	// constructeurs / destructeur
    				explicit shared_ptr_ref(T* p) throw() :ptr(p),count(1){}
    				~shared_ptr_ref(){delete ptr;}
    	// gestion des références
    				void Prend() const throw() {++count;}
    				void Libere(){--count; if(count==0) delete this;}
    	// accès à la donnée interne
    				T* get() const throw(){return ptr;}
    		};
    		mutable shared_ptr_ref* ptr_ref; // référence partagée
    };
     
     
    } // fin du namespace
    #endif


    ville.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
    #ifndef VILLE_H
    #define VILLE_H
    #include <set>
    #include <string>
    #include "shared_ptr.h"
     
    class Logement;
     
    class Ville
    {
        std::set<ag::shared_ptr<Logement> > logements;
     
    public:
        Ville();
        std::string ListeLogements() const;
        Logement* CreeLogement(std::string adresse);
    };
     
    #endif // VILLE_H


    ville.cpp
    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
    #include "ville.h"
    #include "logement.h"
    #include "shared_ptr.h"
    #include <sstream>
    #include <algorithm>
     
    Ville::Ville()
    {
    }
     
    std::string Ville::ListeLogements() const
    {
        std::ostringstream flux;
     
        for(std::set<ag::shared_ptr<Logement>>::iterator i=logements.begin();i!=logements.end();++i)
        {
             flux << (*i)->ToString() << ',';
        }
        return flux.str();
     
    }
     
    Logement* Ville::CreeLogement(std::string adresse)
    {
        ag::shared_ptr<Logement> l = new Logement(adresse);
        logements.insert(l);
    	return l.get();
    }


    main.cpp
    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
    #include <iostream>
    #include "ville.h"
    #include "personne.h"
    #include "logement.h"
     
    using namespace std;
     
    int main()
    {
    	char z;
        cout << "Bienvenue dans ma ville !" << endl;
        Ville city;
        Logement *l1 = city.CreeLogement("15, rue des fleurs");
        Personne p1("paul"),p2("john"),p3("georges"),p4("ringo");
     
        p1.Emmenage(l1);
        p2.Emmenage(l1);
        p3.Emmenage(l1);
        p4.Emmenage(l1);
     
        cout << "Occupants de l1 (normalment 4)"<<endl;
        cout << l1->ListeOccupants() << endl;
     
        Logement *l2 = city.CreeLogement("23 rue des roses");
        p2.Emmenage(l2);
        cout << "Affichage d'une personne :"<<p2.ToString() << endl;
        cout << "Occupants de l1 (3) :"<<l1->ListeOccupants() << endl;
        cout << "Occupants de l2 (1) :"<<l2->ListeOccupants() << endl;
     
        cout << "Liste des logements : ";
        cout << city.ListeLogements()<<endl;
    	cin >> z;
        return 0;
    }


    D'avance merci de votre aide.

  6. #6
    Expert confirmé
    Difficile de répondre sans question précise. Ça ne compile pas? Que dit le compilateur? Ça ne linke pas? Que dit le linkeur? Ça ne fait pas ce qui est attendu? Qu'attend-t-on ? Ça plante ? En faisant quoi et à quel moment ?

    Le ag::shared_ptr<> ne peut pas être mis dans un std::set<> car il n'est pas comparable, ça risque de ne pas compiler ou de donner des résultats bizarres. Il faudrait fournir un foncteur de comparaison à std::set<> ou bien ajouter la possibilité de comparer des ag::shared_ptr<>.
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    template<class T>
    bool operator<( ag::shared_ptr<T> const& g, ag::shared_ptr<T> const& d ) {
        return g.get() < d.get();
    }

  7. #7
    Membre à l'essai
    Merci infiniment dalfab,
    Bravo, ça fonctionne maintenant !