Smart pointeur à compteur de référence

Soyez le premier à donner votre avis sur cette source.

Snippet vu 5 669 fois - Téléchargée 18 fois

Contenu du snippet

Encore un pointeur intelligent, à compteur de référence, qui se comporte à l'utilisation comme un pointeur traditionnel. Attention, il n'est pas threadsafe.
Il a été fait en Builder C++ 2007.

Source / Exemple :


//******************************************************************************
//! @file   TSmartPtr.h
//! @brief  Gestion des pointeurs intelligents
//******************************************************************************

//******************************************************************************
// Version     : 01
// Date        : 11/2008
// Auteurs     : Nirgal76 / Totoche76
// Description :
// - Création de la classe
//******************************************************************************
#ifndef _TSmartPtrH
#define _TSmartPtrH

//******************************************************************************
// MACROS
//******************************************************************************
#define SAFE_DELETE(p)       { if (NULL!=p) { delete p; p=NULL; } }
#define SAFE_DELETE_ARRAY(p) { if (NULL!=p) { delete[] p; p=NULL; } }

//******************************************************************************
// CONSTANTES
//******************************************************************************
const bool C_PTR_ARRAY = true;   //!< Pointeur de base array
const bool C_PTR_SINGLE = false; //!< Pointeur de base simple

//******************************************************************************
//! @class  TSmartPtr
//! @author Nirgal76
//! @author Totoche76
//! @date   11/2007
//! @brief  Classe de gestion de pointeurs intelligents
//******************************************************************************
template <typename T, bool Array = C_PTR_SINGLE>
class TSmartPtr
{
//=====================================
// PUBLIC
//=====================================
public :
//------------------
// CYCLE DE VIE
//------------------
  // Constructeurs
  TSmartPtr();
  // Constructeurs par copie
  TSmartPtr(const TSmartPtr& rSmartPtr);
  // Constructeurs à partir d'un pointeur c++
  TSmartPtr(T* pPointer);
  // destructeur
  ~TSmartPtr();

//------------------
// OPERATEURS
//------------------
  // Opérations sur le pointeur
  TSmartPtr& operator=(const TSmartPtr& rSmartPtr);
  TSmartPtr& operator=(T* pPointer);
  T& operator*();
  T* operator->();
  const T& operator*() const;
  const T* operator->() const;
  bool operator==(const TSmartPtr& rSmartPtr) const;
  bool operator!=(const TSmartPtr& rSmartPtr) const;
  operator T*(void) const;

//=====================================
// PRIVATE
//=====================================
private:
//------------------
// DONNEES
//------------------
  int* mpRefCounter; //!< Nombre de référence sur le pointeur
  T* mpPointer;      //!< Pointeur de base

  //------------------
// METHODES
//------------------
  // Destruteur (par comptage de référence)
  void Release();
}; // fin de TSmartPtr

//******************************************************************************
//! @brief  Constructeur
//!
//! @param  Aucun
//!
//! @return Aucun
//******************************************************************************
template <typename T, bool Array>
inline TSmartPtr<T, Array>::TSmartPtr()
{
  mpRefCounter=NULL;
  mpPointer=NULL;
}// fin du constructeur

//******************************************************************************
//! @brief  Constructeur par copie
//!
//! @param  rSmartPtr : pointeur intelligent à copier
//!
//! @return Aucun
//******************************************************************************
template <typename T, bool Array>
inline TSmartPtr<T, Array>::TSmartPtr(const TSmartPtr<T, Array>& rSmartPtr)
{
  mpPointer = rSmartPtr.mpPointer;
  mpRefCounter = rSmartPtr.mpRefCounter;
  if (NULL!=mpRefCounter)
    ++(*mpRefCounter);
}// fin du constructeur par copie d'un pointeur intelligent

//******************************************************************************
//! @brief  Constructeur par copie d'un pointeur de base
//!
//! @param  pPointer : pointeur de base à copier
//!
//! @return Aucun
//******************************************************************************
template <typename T, bool Array>
inline TSmartPtr<T, Array>::TSmartPtr(T* pPointer)
{
  mpPointer=pPointer;
  if (NULL==mpPointer)
    mpRefCounter = NULL;
  else
    mpRefCounter = new int(1);
}// fin du constructeur

//******************************************************************************
//! @brief  Destructeur
//!
//! @param  Aucun
//!
//! @return Aucun
//******************************************************************************
template <typename T, bool Array>
inline TSmartPtr<T, Array>::~TSmartPtr()
{
  Release();
}// fin du destructeur

//******************************************************************************
//! @brief  Opérateur d'affectation (=)
//!
//! @param  rSmartPtr : pointeur intelligent source
//!
//! @return Le pointeur
//******************************************************************************
template <typename T, bool Array>
inline TSmartPtr<T, Array>& TSmartPtr<T, Array>::operator=(const TSmartPtr<T, Array>& rSmartPtr)
{
  Release();

  mpPointer = rSmartPtr.mpPointer;
  mpRefCounter = rSmartPtr.mpRefCounter;
  if (NULL!=mpRefCounter)
    ++(*mpRefCounter);

  return *this;
}// fin de l'opérateur d'affectation

//******************************************************************************
//! @brief  Opérateur d'affectation (=)
//!
//! @param  pPointer : Pointeur de base
//!
//! @return Le pointeur
//******************************************************************************
template <typename T, bool Array>
inline TSmartPtr<T, Array>& TSmartPtr<T, Array>::operator=(T* pPointer)
{
  Release();

  mpPointer = pPointer;
  if (NULL==mpPointer)
    mpRefCounter = NULL;
  else
    mpRefCounter = new int(1);

  return *this;
}// fin de l'opérateur d'affectation

//******************************************************************************
//! @brief  Opérateur d'égalité (==)
//!
//! @param  rSmartPtr : pointeur intelligent à comparer
//!
//! @return true si les pointeurs sont égaux
//******************************************************************************
template <typename T, bool Array>
inline bool TSmartPtr<T, Array>::operator==(const TSmartPtr<T, Array>& rSmartPtr) const
{
  return mpPointer == rSmartPtr.mpPointer;
}// fin de l'opérateur d'égalité

//******************************************************************************
//! @brief  Opérateur de non égalité (!=)
//!
//! @param  rSmartPtr : pointeur intelligent à comparer
//!
//! @return true si les pointeurs sont différents
//******************************************************************************
template <typename T, bool Array>
inline bool TSmartPtr<T, Array>::operator!=(const TSmartPtr<T, Array>& rSmartPtr) const
{
  return mpPointer != rSmartPtr.mpPointer;
}// fin de l'opérateur de non égalité

//******************************************************************************
//! @brief  Renvoi la valeur du pointeur (opérateur *)
//!
//! @param  Aucun
//!
//! @return Valeur du pointeur
//******************************************************************************
template <typename T, bool Array>
inline T& TSmartPtr<T, Array>::operator*()
{
  return *mpPointer;
}// fin de l'opérateur de valeur

//******************************************************************************
//! @brief  Renvoi la référence du pointeur (opérateur ->)
//!
//! @param  Aucun
//!
//! @return Référence du pointeur
//******************************************************************************
template <typename T, bool Array>
inline T* TSmartPtr<T, Array>::operator->()
{
  return mpPointer;
}// fin de l'opérateur de référence

//******************************************************************************
//! @brief  Renvoi la référence du pointeur (opérateur *) en const
//!
//! @param  Aucun
//!
//! @return Référence const du pointeur
//******************************************************************************
template <typename T, bool Array>
inline const T& TSmartPtr<T, Array>::operator*() const
{
  return *mpPointer;
}// fin de l'opérateur de valeur

//******************************************************************************
//! @brief  Renvoi la référence du pointeur (opérateur ->) en const
//!
//! @param  Aucun
//!
//! @return Référence const du pointeur
//******************************************************************************
template <typename T, bool Array>
inline const T* TSmartPtr<T, Array>::operator->() const
{
  return mpPointer;
}// fin de l'opérateur de référence

//******************************************************************************
//! @brief  Casting sur le pointeur intelligent
//!
//! @param  Aucun
//!
//! @return Pointeur de base
//******************************************************************************
template<typename T, bool Array>
inline TSmartPtr<T, Array>::operator T*(void) const
{
  return mpPointer;
}// fin de l'opérateur de casting

//******************************************************************************
//! @brief  Décrémente le compteur de référence et supprime le pointeur si = à 0
//!
//! @param  Aucun
//!
//! @return Aucun
//******************************************************************************
template <typename T, bool Array>
inline void TSmartPtr<T, Array>::Release()
{
  if (NULL!=mpRefCounter)
  {
    (*mpRefCounter)--;
    if (*mpRefCounter <= 0)
    {// compteur = 0 => destruction du pointeur
      if (Array)
      {// tableau de pointeur
        SAFE_DELETE(mpRefCounter);
        SAFE_DELETE_ARRAY(mpPointer);
      }
      else
      {// pointeur
        SAFE_DELETE(mpRefCounter);
        SAFE_DELETE(mpPointer);
      }
    }// fin de compteur = 0
  }
}// fin de Release

#endif

Conclusion :


Reste à le déclarer. Par exemple, pour déclarer un pointeur sur une classe TMaClasse :
TSmartPtr<TMaClasse> mpMaClasse;

mpMaClasse=new TMaClasse; // Instanciation de TMaClasse
mpMaClasse->Initialiser(); // Fonction membre de TMaClasse
...

Et ensuite, l'utiliser comme un pointeur traditionnel. sauf qu'il n'y a pas à le deleter bien entendu.
Si l'on veut vraiment le supprimer explicitement, lui affecter NULL.

A voir également

Ajouter un commentaire

Commentaires

Messages postés
7
Date d'inscription
vendredi 9 janvier 2009
Statut
Membre
Dernière intervention
16 décembre 2009

>> 1) L'inlining est très efficace (transformation d'une fonction en >>uniquement son corps, donc pas d'appel).

Oui je sais apropos du inline mais d'après ce que je me souviens, pour Windows ou Linux (ou tout autre OS) c'est un appel de fonction spécifique (du OS) pour l'allocation de mémoire heap. Ce qui rend la fonction non-inlinable. Mais comme j'ai dit c'est d'après ce que je me souviens.
Messages postés
7
Date d'inscription
vendredi 9 janvier 2009
Statut
Membre
Dernière intervention
16 décembre 2009

Puisque je construis ma propre classe de smart_ptr (pour des raisons de simplicité et apprentissage) j'ai remarqué que ta fonction release ne fait pas le boulot qu'elle est censée faire (selon le STL). Release en fait devrait avoir comme valeur de retour le pointeur de la memoire alloqué et rendre le pointeur membre "NULL". Ex:

inline T * TSmartPtr<T, Array>::Release()
{
T *pPtr = mpPointer;
mpPointer = NULL; // ou '0' si vous préferez
return pPtr;
}
Messages postés
3813
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
12 juin 2020
107
> La différence je sais n'est pas grande mais moi dans ma tête je me dis vaut mieux faire un if qu'un appel de fonction.
Bof.
1) L'inlining est très efficace (transformation d'une fonction en uniquement son corps, donc pas d'appel).
2) De plus, dans le cas ou le pointeur est différent de null, ce qui est quand même très souvent le cas, tu fais deux fois la vérification.
Messages postés
7
Date d'inscription
vendredi 9 janvier 2009
Statut
Membre
Dernière intervention
16 décembre 2009

Oui NULL est un macro de 0, je l'utilize seulement dans le cas des pointeurs pour les différentier des entiers habituels. Mais apropos de la verification du pointeur avec 0 avant l'appel de delete, je disais que c'était une question de performance parce que justement t'évite te faire un appel à la fonction delete par un if. La différence je sais n'est pas grande mais moi dans ma tête je me dis vaut mieux faire un if qu'un appel de fonction.
Messages postés
2
Date d'inscription
jeudi 6 septembre 2007
Statut
Membre
Dernière intervention
16 décembre 2009

Oui je vais remédier à ça. plutot en l'empêchant d'ailleurs comme c'est une fonctionnalité que je ne vais pas utiliser.

pour NULL, c'est vrai mais j'ai pris l'habitude avec l'aide et les exemples de builder à toujours voir des NULL et du coup, j'ai pris le mauvais pli :/

Merci en tout cas
Afficher les 10 commentaires

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.