Segnalare le eccezioni
Il primo problema che bisogna affrontare quando si verifica un errore e` capire
dove e quando bisogna gestire l'anomalia.
Poniamo il caso che si stia sviluppando una serie di funzioni matematiche, in
particolare una che esegue la radice quadrata. Come comportarsi se l'argomento
della funzione e` un numero negativo? Le possibilita` sono due:
- Terminare il processo;
- Segnalare l'errore al chiamante.
Probabilmente la prima possibilita` e` eccessivamente drastica, tanto piu` che
non sappiamo a priori se e` il caso di terminare oppure se il chiamante possa
prevedere azioni alternative da compiere in caso di errore (ad esempio ignorare
l'operazione e passare alla successiva). D'altronde neanche la seconda possibilita`
sarebbe di per se` una buona soluzione, cosa succede se il chiamante ignora l'errore
proseguendo come se nulla fosse?
E` chiaramente necessario un meccanismo che garantisca che nel caso il chiamante
non catturi l'anomalia qualcuno intervenga in qualche modo.
Ma andiamo con ordine, e supponiamo che il chiamante preveda del codice per gestire
l'anomalia.
Se al verificarsi di un errore grave non si dispone delle informazioni necessarie
per decidere cosa fare, la cosa migliore da farsi e` segnalare la condizione di
errore a colui che ha invocato l'operazione. Questo obiettivo viene raggiunto
con la keyword throw :
int Divide(int a, int b) {
if (b) return a/b;
throw "Divisione per zero";
}
L'esecuzione di throw provoca l'uscita dal blocco in cui essa si
trova (si noti che in questo caso la funzione non e` obbligata a restituire
alcun valore tramite return ) e in queste situazioni si dice che
la funzione ha sollevato (o lanciato) una eccezione.
La throw accetta un argomento come parametro che viene utilizzato
per creare un oggetto che non ubbidisce alle normali regole di scope e che viene
restituito a chi ha tentato l'esecuzione dell'operazione (nel nostro caso al
blocco in cui Divide e` stata chiamata). Il compito di questo oggetto
e` trasportare tutte le informazioni utili sull'evento.
L'argomento di throw puo` essere sia un tipo predefinito che un tipo
definito dal programmatore.
Per compatibilita` con il vecchio codice, una funzione non e` tenuta a segnalare
la possibilita` che possa lanciare una eccezione, ma e` buona norma avvisare
dell'eventualita` segnalando quali tipologie di eccezioni sono possibili. Allo
scopo si usa ancora throw seguita da una coppia di parentesi tonde contenente
la lista dei tipi di eccezione che possono essere sollevate:
int Divide(int a, int b) throw(char*) {
if (b) return a/b;
throw "Errore";
}
void MoreExceptionTypes() throw(int, float, MyClass&) {
/* ... */
}
Nel caso della Divide si segnala la possibilita` che venga sollevata
una eccezione di tipo char* ; nel caso della seconda funzione invece
a seconda dei casi puo` essere lanciata una eccezione di tipo int ,
oppure di tipo float , oppure ancora una di tipo MyClass&
(supponendo che MyClass sia un tipo precedentemente definito).
|