Cerca nel sito:
ricerca
avanzata

Frasi Celebri...

Il gioco degli scacchi ? un insieme di mosse sbagliate.

Andy Soltis 

Sondaggio:

Cosa pensi della pena di morte?

Dovrebbero abolirla in tutto il mondo
A volte ? necessaria
Ammazzateli tutti quei b... delinquenti
Va contro ogni principio umano
Non mi interessa

visualizza risultati


 

Distruttori

Poiche` ogni oggetto ha una propria durata (lifetime) e` necessario disporre anche di un metodo che permetta una corretta distruzione dell'oggetto stesso, un distruttore.
Un distruttore e` un metodo che non riceve parametri, non ritorna alcun tipo (neanche void) ed ha lo stesso nome della classe preceduto da una ~ (tilde):

 

class Trace {
  public:
    /* ... */
    ~Trace() {
      cout << "distruttore ~Trace()" << endl;
    }

  private:
    /* ... */
};

 

Il compito del distruttore e` quello di assicurarsi della corretta deallocazione delle risorse e se non ne viene esplicitamente definito uno, il compilatore genera per ogni classe un distruttore di default che chiama alla fine della lifetime di una variabile:

 

void MyFunc() {
  TVar A;
  /* ... */
}               // qui viene invocato automaticamente
                // il distruttore per A

 

Si noti che nell'esempio non c'e` alcuna chiamata esplicita al distruttore, e` il compilatore che lo chiama alla fine del blocco applicativo (le istruzioni racchiuse tra { } ) in cui la variabile e` stata dichiarata (alla fine del programma per variabili globali e statiche). Poiche` il distruttore fornito dal compilatore non tiene conto di aree di memoria allocate tramite membri puntatore, e` sempre necessario definirlo esplicitamente ogni qual volta esistono membri puntatori; come mostra il seguente esempio:

 

#include < iostream >
using namespace std;

class Trace {
  public:
    /* ... */
    Trace(long double);
    ~Trace();

  private:
    long double * ldPtr;
};

Trace::Trace(long double a) {
  cout << "costruttore chiamato... " << endl;
  ldPtr = new long double(a);
}

Trace::~Trace() {
  cout << "distruttore chiamato... " << endl;
  delete ldPtr;
}

 

In tutti gli altri casi, spesso il distruttore di default e` piu` che sufficiente e non occorre scriverlo.
Solitamente il distruttore e` chiamato implicitamente dal compilatore quando un oggetto termina il suo ciclo di vita, oppure quando un oggetto allocato con new viene deallocato con delete:

 

void func() {
  Trace A(5.5);                 // chiamata costruttore
  Trace* Ptr=new Trace(4.2);    // chiamata costruttore
  /* ... */
  delete Ptr;                   // chiamata al
                                // distruttore
}                               // chiamata al
                                // distruttore per A

 

In alcuni rari casi puo` tuttavia essere necessario una chiamata esplicita, in questi casi pero` il compilatore puo` non tenerne traccia (in generale un compilatore non e` in grado di ricordare se il distruttore per una certa variabile e` stato chiamato) e quindi bisogna prendere precauzioni onde evitare che il compilatore, richiamando il costruttore alla fine della lifetime dell'oggetto, generi codice errato.
Facciamo un esempio:

 

void Example() {
  TVar B(10);
  /* ... */
  if (Cond) B.~TVar();
}                         // Possibile errore!

 

Si genera un errore poiche`, se Cond e` vera, e` il programma a distruggere esplicitamente B, e la chiamata al distruttore fatta dal compilatore e` illecita. Una soluzione al problema consiste nell'uso di un ulteriore blocco applicativo e di un puntatore per allocare nello heap la variabile:

 

void Example() {
  TVar* TVarPtr = new TVar(10);
  {
    /* ... */
    if (Cond) {
      delete TVarPtr;
      TVarPtr = 0;
    }
    /* ... */
  }
  if (TVarPtr) delete TVarPtr;
}

 

L'uso del puntatore permette di capire se la variabile e` stata deallocata (nel qual caso il puntatore viene posto a 0) oppure no (puntatore non nullo).
Comunque si tenga presente che i casi in cui si deve ricorrere ad una tecnica simile sono rari e spesso (ma non sempre) denotano un frammento di codice scritto male (quello in cui si vuole chiamare il distruttore) oppure una cattiva ingegnerizzazione della classe cui appartiene la variabile
Si noti che poiche` un distruttore non possiede argomenti, non e` possibile eseguirne l'overloading; ogni classe cioe` possiede sempre e solo un unico distruttore.

 

 

successivo
–«  INDICE  »–

 

 

 

 
Powered by paper&pencil (carta&matita ) - Copyright © 2001-2019 Cataldo Sasso