Smart pointeur à compteur de référence

Soyez le premier à donner votre avis sur cette source.

Snippet vu 6 486 fois - Téléchargée 21 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
BloodReapR Messages postés 6 Date d'inscription vendredi 9 janvier 2009 Statut Membre Dernière intervention 16 décembre 2009
16 déc. 2009 à 19:16
>> 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.
BloodReapR Messages postés 6 Date d'inscription vendredi 9 janvier 2009 Statut Membre Dernière intervention 16 décembre 2009
16 déc. 2009 à 19:05
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;
}
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 124
16 déc. 2009 à 17:45
> 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.
BloodReapR Messages postés 6 Date d'inscription vendredi 9 janvier 2009 Statut Membre Dernière intervention 16 décembre 2009
16 déc. 2009 à 17:41
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.
nirgal76 Messages postés 2 Date d'inscription jeudi 6 septembre 2007 Statut Membre Dernière intervention 16 décembre 2009
16 déc. 2009 à 16:58
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

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.