Smart pointer

Contenu du snippet

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 !!!!)

A voir également

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.