View Single Post
Old 28-07-2005, 21:38   #2
fek
Senior Member
 
L'Avatar di fek
 
Iscritto dal: Oct 2002
Cittā: San Jose, California
Messaggi: 11794
Quote:
Originariamente inviato da ri
quindi mi sorge la domanda: č il dogma sbagliato (o troppo rigido) o mi sfugge qualcosa?
Il dogma cosi' come lo hai enunciato e' parzialmente errato (o parzialmente giusto).

E' sacrosanto non sollevare mai un'eccezione in un distruttore.
I motivi sono vari, uno dei piu' importanti e':

- quando viene sollevata un'eccezione, per Standard C++, gli oggetti locali sullo stack dal punto in cui viene sollevata l'eccezione al punto in cui viene gestita sono distrutti invocando il distruttore (Stack Unwinding); che succede se uno di questi distruttori solleva a sua volta un'eccezione?

Si scatena il panico e sei nella terra dell"Undefined Behavior". Di solito i compilatori C++ chiamano immediatamente terminate() perche' non c'e' modo di uscire da quella situazione. Ma lo Standard non lo impone ed ogni compilatore e' libero di fare quello che gli pare.

Il discorso sul costruttore invece e' diverso; e' buona norma lanciare un'eccezione da un costruttore per riportare una situazione d'errore che ti impedisce di costruire l'oggetto in maniera corretta; ed e' una situazione che accade piuttosto spesso.
Ci sono vari modi per risolverla, ma nessuno e' elegante e semplice da implementare come sollevare un'eccezione, perche' lo Standard C++ in questo caso ti viene in aiuto, imponendo che in caso di eccezione durante la creazioen di un'oggetto dinamico, l'operatore new ritorna NULL.

Esempio:

Codice:
A* a;

try 
{
  a = new A();
}
catch (...)      // non fatelo mai, indicate sempre l'eccezione di cui fare il trap
{
   // a qui e' uguale a NULL perche' e' stata sollevata un'eccezione 
   // nel costruttore e qualcosa e' andato storto
}
 
if (a == NULL)  // E quanto ci starebbe bene qui un NULL Object Pattern?
{
   printf("AAAAAAAAAAAARGH!!!");
}
Senza eccezioni la soluziona sarebbe stata un po' meno elegante:

Codice:
A* a = new A();

// Devo creare un metodo IsValid() solo per riportare la condizione d'errore

if (!a->IsValid())  
{
   // E se dimentico di distruggere l'oggetto esplicitamente? LEAK!
   delete a;
   a = 0;
}

if (a == 0)
{
  printf("AAAAAAAAAAAAARGH");
}
fek č offline   Rispondi citando il messaggio o parte di esso