#ifndef SMART_POINTER #define SMART_POINTER #include <assert.h> #include <stdlib.h> #include <string> class Counted { public: Counted() : ref_count_(0) {} // a la creation 0 pointeurs referencent notre objet virtual ~Counted(){assert(ref_count_==0);} // on verifie que 0 pointeurs pointent sur notre objet void add_ref(){ref_count_++;} // ajoute une reference au compteur void release_ref(){ref_count_--;} // enleve une reference au compteur int ref_count() const {return ref_count_;} // renvoie le nombre de pointeurs pointant sur notre objet private: int ref_count_; // le nombre de pointeurs referencant notre objet }; template<class Nimp> class SmartPointer { public: SmartPointer():ptr_(NULL){} // constructeur vide : aucun pointeur virtual ~SmartPointer(){release();} // le desctructeur "relache" l'objet pointé SmartPointer(const SmartPointer & sp) : ptr_(NULL){(*this) = sp;} // constructeur par copie : idem que le constructeur // vide suivi d'un appel à l'operateur = SmartPointer(Nimp * n) : ptr_(NULL){(*this) = n;} // constructeur avec un objet pointé en parametre // idem que l'operateur = avec un objet en param bool is_null()const{return ptr_==NULL;} // test si le pointeur est NULL void operator = (Nimp * n){ if(n==ptr_) return; // on pointe deja sur cet objet release(); // on relache le ptr courant acquire(n); // on recupere le nouveau pointeur } void operator = (const SmartPointer & sp){ if(this == &sp) return; // l'utilisateur fait nimporte quoi ! (p1 = p1;) (*this) = sp.ptr_; // on lance l'operateur = sur l'objet } bool operator == (const SmartPointer & sp){return ptr_ == sp.ptr_;} // test si les pointeur sont les memes bool operator != (const SmartPointer<Nimp> & sp){ return ptr_ != sp.ptr_; } // test si les pointeur sont != Nimp * operator -> () const{ assert(ptr_!=NULL&&"Null pointer access"); return ptr_; } // simule l'operateur -> avec un petit test si le ptr est egal à NULL Nimp & operator * () const{ assert(ptr_!=NULL&&"Null pointer access"); return *ptr_; } // simule l'operateur * avec un petit test si le ptr est egal à NULL private: // relache l'objet pointé void release(){ if(ptr_==NULL) return; ptr_->release_ref(); // on enleve une reference au compteur de l'objet if(ptr_->ref_count()==0) // si plus aucun pointeur ne referencie l'objet delete ptr_; // on le delete ptr_ = NULL; } void acquire(Nimp * n){ if(ptr_!=NULL) release(); // on relache le pointeur courant if(n==NULL) return; ptr_ = n; ptr_->add_ref(); // on ajoute une reference sur le compteur de l'objet } Nimp * ptr_; // l'objet pointé }; // Petit test de notre classe SmartPointer // Pour tester ca, ecrire cela dans le main : // int main(int argc, _TCHAR* argv[]){ // Test::test(); // return 0; // } class Test : public Counted { public: // construit l'objet test Test(const std::string & s):s_(s) {std::cout <<"constructor " <<s_ <<std::endl;} // detruit l'objet test ~Test(){std::cout <<"destructor " <<s_ <<std::endl;} // un petit typedef pour se simplifier // l'utilisation du SmartPointer de Test typedef SmartPointer<Test> TestPtr; static void test(){ // construit un nouveau ptr p1 std::cout <<"new p1" <<std::endl; TestPtr p1 = new Test("toto"); // construit un nouveau ptr p2 std::cout <<"new p2" <<std::endl; TestPtr p2 = new Test("titi"); // p1 et p2 pointent sur le meme objet // => detruit l'ancien objet pointé par p1 (toto) // car plus aucun pointeur ne referencie toto std::cout <<"p1 = p2" <<std::endl; p1 = p2; std::cout <<"exit" <<std::endl; // fin de la portee de p1 et p2 // les destructeur p1 et p2 sont appelés // et titi est detruit } private: std::string s_; // bahhhh }; #endif
heu excuse moi, mais moi aussi j'utilise les compteur de reference dans mes allocation, seulement ce n'est pas des classes.Mais le probleme des liste chainees marchge tres tres bien, moi je ne voix pas pourquoi ca ne marcherai pas, et comme c'est lez cas, ce n'est pas normal.
Essayes le code suivant :class List {public: struct Node : public Counted{ SmartPointer<Node> prev, next; ~Node(){nb_inst--;} Node(){nb_inst++;} static int nb_inst; }; SmartPointer<Node> root; static void test(){ { List l; l.root = new Node(); l.root->next = new Node(); l.root->next->prev = l.root; l.root->next->next = new Node(); l.root->next->next->prev = l.root->next; } assert(Node::nb_inst==0); }};int List::Node::nb_inst = 0;Bon, bien, sur si tu remet à NULL tout les prev, ca revient dans l'ordre ...Petite question, tout de meme : si c'est pas des classes, que tu utilises, c'est quoi alors ?
bah en fait tu fais une surcouhe des malloca chaque fois que l'utilisateur alloue, tu coole avant sa strucutr une aute suture a toi (HEADER) qui contient les nombres de pointeues de reference, et de pluys je conserve le nom du fichier et la ligne de l'allocation, et aussi je chaine toute les allocation, comme cela a la fin de mon programme je liste toute les allocation qui n'ont pas ete allouees, et je sais lesquelles c'est !Moi ca me debug tres bien.
malloc c'est du C ... ici on parle de C++ => newsinon c pas une copie de l'auto_ptr de la STL ca des fois ? :p
bah ... et alors ??? moi mes trucs font exatement la meme chose que ceux de cette source ! De plus ils contiennent plus d'infomration de debug, donc je ne foi pas ou est le probleme, surtout comme c'est du C, c'est protable C++ !!
> sinon c pas une copie de l'auto_ptr de la STL ca des fois ? :pNan : je viens de regarder comment marche le auto_ptr. Tu n'as pas de comptage de reference. Je te fais un copier / coller de l'operateur = entre 2 auto_ptr : auto_ptr<_Ty>& operator=(auto_ptr_ref<_Ty>& _Right) throw () { // assign compatible _Right._Ref (assume pointer) reset(_Right._Ref.release()); return (*this); }Il fait un release sur le auto_ptr right. Ca veut dire que ce code plante : typedef std::auto_ptr<double> DoublePtr; DoublePtr p1(new double(5.0)); DoublePtr p2 = p1; std::cout << *p1 <<std::endl;Car p1 n'est plus valide. Avec ces SmartPointer, tu peux avoir plusieurs pointeurs pointant en meme temps sur le même objet.
> bah ... et alors ???Je suis d'accord pour le debugging. Par contre tu ne peux pas redefinir l'operator = en C. Alors je vois pas l'interet de faire un smart pointer ! Peut etre que j'ai mal compris ta facon de faire ... Fait donc un post de ton code.
c'est du C, c'est protable C++ >> si tu savais les difficultés qu'on peut rencontrer en encapsulant du c dans du c++ ...ok tibur :)ds les lib boost il y a 5 smart pointers aussi pour ceux que ca interresse :)www.boost.org
Du classique ;-)Pour approfondir le sujet, la meilleure référence AMA reste 'More Effective C++ de Scott Meyers, chez Addison-Wesley. Les items 28 et 29, traitent exactement de ce sujet, avec le code en prime. Quelques remarques sur le code néanmoins :- Quand on inclue des fichiers d'entête C, il est mieux d'utiliser ceux conçus pour le C++, qui encapsulent les fonctions standard dans le namespace std. Donc <assert.h>, et <stdlib.h> deviennent <cstdlib>, <cassert>- On n'utilise pas NULL en C++, on utilise 0. Y'a une grande justification derriere tout cela, assez technique d'ailleurs.- Tester si un smart pointer est nul est un point délicat. L'implémentation proposée ici utilise une fonction membre. C'est bien, cependant cela pose un problème. Le Smart Pointer ne se comporte plus comme un pointeur. Le principe d'une bonne implémentation de Smart Pointer est qu'il puisse se substituer de manière transparente à un pointeur classique. Là ce n'est pas le cas. La solution proposée en général est d'implanter l'opérateur operator!. Ce qui permet d'écrire: if (!ptr) {/* Pointeur ou SmartPointer non null*/}- Je ne vois pas l'intérêt de définir le destructeur comme virtuel. Au contraire. La classe n'a pas a priori vocation à être surchargée, est ne définir aucune fonction virtuelle fera l'économie de la création de la vtable. Ce qui est plutot souhaitable pour une classe dont les instances se substituent à un type scalaire.
Se souvenir du profil
Mot de passe oublié ? / Activation de compteCréer un compte
1 873 737 membres 31 nouveaux aujourd'hui 16 151 membres club