Voila comment se debarasser definitevement des pointeurs dans vos programmes C++.
Permet d'eviter tout les problemes de memoire (fuite, NULL access et acces une zone de memoire deja deletée)
Enjoy !
Source / Exemple :
#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
Conclusion :
Bon, j'ai fait des efforts : j'ai ajouté pleins de commentaires !
Petite note pour les experts : ce type de pointeurs n'est pas utilisable dans les liste doublement chainées !
imaginons la class Node :
class Node : public Counted {
public : (...)
private:
SmartPointer<Node> prev_, next_;
}
Si vous utilisez mes SmartPointer avec ce Node, ca chiera !
Je vous laisse cogiter à l'explication...
(Faut que j'aille faire à manger !!!!)
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.