Newsgroup: it.comp.lang.c++
Titolo: La Gestione delle eccezioni in C++

Su tutti i testi di c++ si trova scritto che la gestione degli errori dovrebbe essere fatta sfruttando il meccanismo delle eccezioni piuttosto che restituendo dei codici.
 
In realtà provando ad utilizzarle nello sviluppo di una libreria mi sono ritrovato a scrivere codice del genere:
 
 
void FaiQualcosa(...)
{
    if (Test1)
    {
        if (Test2)
        {
            // fai quello che devi;
            return;
        }
        throw Exception2(...);
    }
    throw Exception1(...);
}
 
che non mi pare molto diverso da scrivere:
 
 
int FaiQualcosa(...)
{
    if (Test1)
    {
        if (Test2)
        {
            // fai quello che devi;
            return OK;
        }
        return ERR2;
    }
    return ERR1;
}
 
Mi chiedo allora se non sia necessario modificare il proprio stile di programmazione, ad esempio cosí:
 
void FaiQualcosa(...)
{
    ControllaTest1(...)    // Lancia Exception1 se non il test non passa
    ControllaTest2(...)    // Lancia Exception1 se non il test non passa
    // fai quello che devi;
}
 
La funzione effettivamente è più breve e comprensibile. Si può fare di meglio?
 
Inoltre, non c'è modo di sapere dalla signature di FaiQualcosa(...) che potrebbe lanciare 2 tipi di eccezioni; oltre a segnalarlo nella documentazione della libreria esiste qualche altro metodo?
 
Infine, se lo sviluppatore si dimentica di gestire un eccezione inserendo nel codice client il relativo blocco try/catch, il compilatore non visualizza neppure un warning e nel caso in cui l'eccezione venga lanciata il codice va in crash senza fornire alcuna informazione. Esiste una strategia di programmazione per scrivere del codice client che possa mettersi al riparo da questo problema?
 
Grazie mille.
 
 

 proprio stile di programmazione, ad esempio cosí:
 
Io vedo che scrivo più roba e tutto è lievemente più
macchinoso con le eccezioni. Ma fa comodo il fatto che
puoi intercettarle in modo selettivo lungo la catena delle
chiamate, quale vuoi e dove vuoi, cosa che in progetti
complessi penso sia meglio. Però ammetto che in casi
"quick & dirty" ricorro al return.
 
ciao
 
Apx.
 
-- 
"La teoria è sapere come funzionano le cose e
non sapere come farle funzionare; la pratica è
sapere come far funzionare la cose senza sapere come
funzionano; il nostro scopo è unire la pratica
alla teoria per riuscire a non far funzionare
le cose senza capire come abbiamo fatto"
 


No aspetta, stai usando male uno strumento.
Che le eccezioni in C++ non servono è come dire che non serve il "do" in C. Tutto si può fare solo quattro/cinque istruzioni macchina (e qui sfido i presenti ;) hint: brainf**k anyone?) ma se c'è una sovrastruttura in più bisogna usarla per come è stata pensata.
Se sei in dubbio su un caso d'uso ti consiglio di postare quello, così magari viene fuori il "modo C++" di implementarlo!
Ciao!


 
 
-- 
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)
 

 
 
Ci sono varie filosofie in tal senso, ma la più widespread è quella di gestire l'eccezione più vicino possibile al punto dove è stata generata; se l'eccezione non può gestire si rilancia un'altra eccezione al livello superiore, e così via.
Tutto questo perché?
A volte una classe può gestire le eccezioni delle classi contenute (tipo "ho finito la memoria, distruggo tutto"), altre volte no ("non sono riusciuto ad inizializzare la classe di core e non ho altre possibilità - devo morire"). In C++ questa classe che gestisce questa specifica cosa potrebbe essere una implentazione di una interfaccia di livello superiore che ha anche altre implementazioni che gestiscono le eccezioni diversamente.
So che all'inizio può essere complesso (e io non sono un gran che a spiegarmi) ma, usando bene il meccanismo delle eccezioni, molti problemi computazionalmente difficili diventano facili a livello di linguaggio.
Ciao!

 Non ricordo più la sintassi, ma se cerchi la troverai.
 
non sapevo esistesse ma sapendo da te cosa cercare l'ho 
trovata.
 
http://www.cplusplus.com/doc/tutorial/exceptions/
 
 
certo, è roba da librerie software-eurofighter ma in
effetti potrebbe essere utile anche a livello didattico.
 
ciao!


Grazie a tutti per le risposte.
 
Purtroppo la specifica dell'eccezione nella signature sembrerebbe sconsigliata, perché causa di notevoli problemi: fondamentalmente equivale a dichiarare che una funzione lancia solo l'eccezione dichiarata e nel caso in cui dovesse lanciare direttamente o indirettamente un eccezione di tipo diverso questa non potrebbe essere trappata in alcun modo.
 
Rimane quindi il problema: come capire se un'applicazione va in crash a seguito di una eccezione non gestita? e chi l'ha lanciata? Il codice delle librerie potrebbe non essere disponibile e gli header di scarso aiuto.
 
Mi sembra che, nello sviluppo di una libreria, l'unico modo per alleggerire il problema, sia quello di documentare bene i metodi delle classi, magari con doxygen specificando sempre tutte le eccezioni; altrimenti sarebbe veramente possibile dimenticare qualche blocco try/catch. Inoltre forse potrebbe aiutare derivare tutte le proprie eccezioni da una classe base, ad esempio "NomelibreriaException" e includere nel main qualcosa del genere:
 
int main()
{
 try
 {
    // codice dell'applicazione con le chiamate alla libreria
 }
 catch (NomelibreriaException& ex)
 {
    std::cerr << ex.what();
 }
 catch (...)
 {
    throw std::exception("Eccezione sconosciuta");
 }
}
 
Forse in questo modo in caso di crash avrei qualche info in più.


 di scarso aiuto.
 
Capire se è un'eccezione non gestita mi pare fattibile:
basta scrivere almeno il solo "main" nella forma
try/catch(...) e inserire un printf nel blocco.
 
Capire chi ha lanciato cosa, credo sia non solo difficile
ma nemmeno una buona cosa in sé: penso a delle librerie
importanti in cui sapere che eccezioni vengono lanciate
potrebbe facilitare il reverse engineering. Se invece
un'eccezione è documentata il problema non si pone...


 Forse in questo modo in caso di crash avrei qualche info in più.
 
si, se sai per certo che NomelibreriaException supporta un 
metodo what :-).
Non avevi detto che la libreria non è documentata ?
Se la scrivi tu, puoi anche controllare se vengono generate, 
dove e quali, le eccezioni.
Se non hai il codice e gli header sono poco chiari, ti resta 
solo il catch generico ...
ciao
CCCP



 se lo sviluppatore si dimentica di gestire un eccezione inserendo nel codice client il relativo blocco try/catch, il compilatore non visualizza neppure un warning e nel caso in cui l'eccezione venga lanciata il codice va in crash senza fornire alcuna informazione. Esiste una strategia di programmazione per scrivere del codice client che possa mettersi al riparo da questo problema?
 
Una lib ben fatta dovrebbe (idealmente) occuparsi di una serie ben 
precisa di cose senza scocciare il main con i dettagli di quello che fa.
 
Per cui non ha molto senso riportare una eccezione fuori da una 
libreria: senza i dettagli, cosa può fare il main che la lib non abbia 
già fatto di suo? Una cosa sola: annullare l'operazione e cercare altre 
strategie per fare quello che deve fare.
Per questo, un error code di ritorno basta e avanza.
 
E poi ci sarebbe il fatto che una lib deve essere usata anche da 
linguaggi che le eccezioni C++ manco sanno cosa sono, per cui non 
reagirebbero bene a una eccezione lanciata dalla libreria :-)
 
 

 
On 09/21/12 22:26, Soviet_Mario wrote:
 
Mi scuso in anticipo se rispondo un po' ad entrambi...
 
 
 
 
 
 >> Purtroppo la specifica dell'eccezione nella signature sembrerebbe
 >> sconsigliata
 
Piu' che altro pare sia stata "deprecated" nell'ultimo standard.
 
 >> perché causa di notevoli problemi
 
Si', soprattutto perche' la maggior parte dei programmatori non ha 
capito cos'era veramente.
 
 > fondamentalmente
 >> equivale a dichiarare che una funzione lancia solo l'eccezione
 >> dichiarata
 
Esatto.
 
 >> e nel caso in cui dovesse lanciare direttamente o
 >> indirettamente un eccezione di tipo diverso questa non potrebbe essere
 >> trappata in alcun modo.
 
Falso, vedi:
http://www.cplusplus.com/reference/std/exception/bad_exception/
.
http://www.cplusplus.com/reference/std/exception/unexpected_handler/
 
http://www.cplusplus.com/reference/std/exception/set_unexpected/
 
 
 
 
 
 
 > Pensavo invece che quella dichiarazione fosse una forte "hint" al
 > compilatore
 
Non e' un suggerimento, ma un'indicazione che il compilatore dovrebbe 
seguire alla lettera.
Poi non tutti i compilatori lo fanno, ad es. MicroSoft: non so nelle 
ultime versioni, ma ricordo che, ad esempio, VC8 gestiva solo i "throw 
()", ma emetteva un warning sui "throw (qualcosa)", dicendo che non 
erano implementati e sarebbero stati ignorati.
 
 > in modo che l'eventuale lancio di eccezioni dalla funzione
 > stessa e da tutte le sue dipendenze potesse essere controllata a
 > compile-time, e che in caso di mismatch tra le throw effettive ed il
 > "contratto", potesse portare ad errore di compilazione.
 
Appunto: questo e' quello che intendevo sopra, riguardo al modo 
sbagliato in cui molti l'avevano capito. :)
Quello che dici tu e' quello che succede in Java; in C++ le specifiche 
di eccezione NON vengono controllate in fase di compilazione, ma di 
esecuzione.
 
 > Se così non è ... allora non capisco affatto il senso della direttiva.
 
Francamente neanch'io l'ho mai trovata utile.
Al massimo trovo utile un "throw ()", ma se fosse un commento accanto 
alla funzione sarebbe uguale.
 
 > Se è come dici, mi pare un costrutto pericolosissimo : dichiari una
 > garanzia, e te ne devi fare carico a mano, garantendo anche per strati
 > sottostanti. Un ginepraio.
 
Esattamente: prometti qualcosa che, molto spesso, non potrai mantenere.
Del resto vedi i link sopra: in sostanza ci si attende l'inatteso.
 
 
 
 
 
 >> Rimane quindi il problema: come capire se un'applicazione va in crash
 >> a seguito di una eccezione non gestita? e chi l'ha lanciata?
 
Normalmente i debugger consentono di fermare il programma al lancio di 
un'eccezione (es. "catch throw" in gdb).
 
 > beh, cmq si può tentare di trappare a prescindere dall'avere sicurezza
 > di come si comportano gli strati sottostanti.
 
Mia opinione personale: salvo rari casi, non solo si "puo'", ma si "deve".
 
 
 
 
 > se non dichiarano niente come contratto, dal documento che ha postato
 > Archaeopterix parrebbe che la funzione garantisca di non lanciare
 > niente.
 
Falso anche questo.
E' cosi' (in parte) in Java.
In C++ una funzione promette di non lanciare niente se e' dichiarata 
come "throw ()" (che poi lo mantenga e' un altro discorso).
Una funzione che non ha specifiche riguardo a cosa lancia, si assume 
debba lanciare qualunque cosa.
 
 
 
 
 
 >> Mi sembra che, nello sviluppo di una libreria, l'unico modo per
 >> alleggerire il problema, sia quello di documentare bene i metodi delle
 >> classi,magari con doxygen
 
Il che non guasta mai :)
 
 >> specificando sempre tutte le eccezioni;
 >> altrimenti sarebbe veramente possibile dimenticare qualche blocco
 >> try/catch.
 
Metticene sempre uno generico (cacth (...)) e vivi felice.
 
 >> Inoltre forse potrebbe aiutare derivare tutte le proprie
 >> eccezioni da una classe base, ad esempio "NomelibreriaException" e
 >> includere nel main qualcosa del genere:
 
E' per quello che esiste std::exception.
Solo che non e' obbligatorio derivare da essa, da cui la necessita' dei 
"catch (...)".
 
 
 
 
  bye
     av.
 

On 09/22/12 14:11, Massimo Soricetti wrote:
 
 > Per questo, un error code di ritorno basta e avanza.
 
Basta, avanza, ma e' piu' scomodo.
 
 
 
 > E poi ci sarebbe il fatto che una lib deve essere usata anche da
 > linguaggi che le eccezioni C++ manco sanno cosa sono
 
Questo non e' sempre detto.
 
 
 
 > per cui non reagirebbero bene a una eccezione lanciata dalla libreria :-)
 
In tal caso probabilmente si utilizzerebbe un wrapper.
 
 
 
  bye
     av.
 


 
Per esempio?


 
 


On 09/23/12 11:26, Soviet_Mario wrote:
 >>  > E poi ci sarebbe il fatto che una lib deve essere usata anche da
 >>  > linguaggi che le eccezioni C++ manco sanno cosa sono
 >>
 >> Questo non e' sempre detto.
 >
 > più che altro, quando l'interoperabilità è effettivamente un requisito,
 > ESPORRE eccezioni è un nonsense di design.
 
Non concordo.
Vedi ad esempio IDL (CORBA): li' le eccezioni esistono, pur trattandosi 
di un linguaggio nato per consentire l'interoprabilita'.
 
Stesso discorso per XML-RPC ed immagino altri.
 
  bye
	av.

On 09/22/12 18:50, Massimo Soricetti wrote:>>  > per cui non 

Prendiamo il C...
 
void foo(); //Funzione C++ che puo' lanciare eccezioni
extern "C" int c_foo() {
   try {
     foo();
     return 0;
   } catch (...) {
     return 1;
   }
}
 
In questo modo hai il fardello dei codici di ritorno solo laddove e' 
effettivamente inevitabile.
 
  bye
	av.


ma tutti i linguaggi di programmazione sono progettati per 
saper intercettare le eccezioni lanciate da una libreria C++ 
? Sono un po' sconcertato ...


 intercettare le eccezioni lanciate da una libreria C++ ?
 
No, assolutamente.
Ma ci possono essere strati di conversione che le trasformano in 
eccezioni di quel linguaggio.
Spesso hai delle limitazioni su quali eccezioni puoi lanciare e, se esci 
da questo schema, la tua eccezione viene convertita in una generica.
Bisognerebbe pero' vedere caso per caso...
 
  bye
	av.

 effetti potrebbe essere utile anche a livello didattico.
 
Direi che pagare la scomodita' di un linguaggio legnoso come C++ senza
usarne al massimo le feature sia un vero spreco. 
 
nothrow si usa di rado (e' una garanzia molto forte da fare), ma per chi
usa il tuo codice quel tipo di cose possono volere dire molto.
 
-- 
-riko
http://www.enrico-franchi.org/
 
http://rik0-techtemple.blogspot.com/
 

 potrebbe facilitare il reverse engineering. 
 
Davvero... il reverse engineering delle librerie? Questi sono tutti
falsi problemi. E qualcuno che mi desse una cattiva gestione dell'errore
per rendermi piu' difficile fare RE della sua libreria non mi avrebbe
per cliente.
 
Cioe' cosa ci faccio? Riscrivo la libreria? Ma non dovevo gia' finire il
mio progetto? Se potevo permettermi di scrivere la libreria l'avrei
scritta, no? :) 


 alla funzione sarebbe uguale.
 
Dal punto di vista dell'utente si. La mia idea e' che sotto si pensava
di poter usare la cosa per ottimizzare.
 
Se ci pensi, molta ricerca sui compilatori e' andata perche' stabilire
il meccanismo di gestione dell'eccezioni ha un costo anche se non si
usano le eccezioni e si voleva minimizzare tale costo nel caso in cui le
eccezioni non venivano lanciate. Questo oggi e' fatto, tipicamente.
 
In pratica se tu dichiari un throw (), vuole dire che qualunque codice
il compilatore dovrebbe generare per poter gestire le eccezioni interne
alla funzione, lui *non* deve generarlo.
 
Poi sono d'accordo... dal punto di vista dell'utente basterebbe fosse
un'annotazione della documentazione. Il compilatore pero' puo' farci
qualcosa, almeno in teoria. Non so se attualmente tali dichiarazioni
siano usate in tal senso.


 vantaggi di un costrutto non locale e che sembra pure asincrono.
 
La domanda e'... ma sono l'unico ad essersi dannato con codice C scritto
per non scoppiare incontrollatamente dove praticamente *ogni* chiamata a
funzione in una funzione deve controllare i valori di ritorno? E
ovviamente a questo punto praticamente la cosa piu' leggibile passa per
dei goto a zone di gestione dell'errore -- e veramente, quando si dice
che il resto e' peggio del goto si sta dicendo qualcosa --.
 
Insomma, perche' dopo averci lavorato un po' mi verrebbe da dire che
l'uso delle eccezioni e' tutto meno che goffo.


On 09/25/12 19:17, Enrico Franchi wrote:
 > La domanda e'... ma sono l'unico ad essersi dannato con codice C scritto
 > per non scoppiare incontrollatamente dove praticamente *ogni* chiamata a
 > funzione in una funzione deve controllare i valori di ritorno?
 
No, vai tranquillo, ne vedo spesso di masochisti :)
O in alternativa di ottimisti...
 
 
 
 
 > Insomma, perche' dopo averci lavorato un po' mi verrebbe da dire che
 > l'uso delle eccezioni e' tutto meno che goffo.
 
Per quanto ho visto finora, chi non usa le eccezioni (e il RAII, ecc...) 
lo fa perche' non le conosce o non le ha capite. Quasi sempre perche' 
non ha voluto spenderci cinque minuti (e spesso insiste a non volerlo fare).
Certo non puoi impedire a tutti di farsi del male da soli...
 
 
 
  bye
	av.

 
On 09/25/12 19:17, Enrico Franchi wrote:
 
 > In pratica se tu dichiari un throw (), vuole dire che qualunque codice
 > il compilatore dovrebbe generare per poter gestire le eccezioni interne
 > alla funzione, lui *non* deve generarlo.
 
Interessante, pero' mi lascia perplesso.
 
Io infatti posso scrivere:
 
char*a(int b) throw() {
   return new char[b];
}
 
Chiaramente sto mentendo: asserisco che questa funzione non genera 
eccezioni, ma in realta' e' facile prevedere un bad_alloc.
Ribadisco: sono io che sbaglio, ma questo sbaglio mi e' consentito.
 
Ora, alla generazione di una bad_alloc dovrebbe essere chiamato 
l'handler per le eccezioni inattese, ecc... quindi il compilatore 
dovrebbe comunque generare tutta questa gestione.
 
Se, come dici, il compilatore non genera tale codice, secondo me, si va 
fuori standard ed il comportamento del programma diventa davvero imprevisto.
 
Sbaglio?
C'e' una qualche clausola nello standard che dice che in caso di 
eccezione in una funzione nothrow tutta questa gestione non deve essere 
fatta?
Cosa succede allora nel caso sopra?
 
  bye
     av.

 Cosa succede allora nel caso sopra?
 
Allora: io parlo di throw (). Lo standard mi dice che se la new la sopra
lancia un'eccezione, allora viene chiamata unexpected(). Ad unexpected()
non e' consentito di ritornare (altrimenti si viola lo standard). Quello
che puo' fare e' esclusivamente:
 
1. lanciare un'eccezione consentita (in questo caso nessuna). se questo
potesse avvenire allora si dovrebbe riprendiere a cercare l'exception
handler corretto.
2. se lo specificatore contiene std::bad_exception, allora viene
essenzialmente convertita in un eccezione ID di tipo bad_exception (ma
non e' il nostro caso).
3. se lo specificatore *non* contiene bad_exception, allora viene
chiamato terminate.
 
Riguardo a terminate, lo standard consente di abbandonare il
tradizionale exception handling, fra le varie cose, quando unexpected
lancia un'eccezione non consentita. In questo caso, viene chiamata
terminate() *senza* fare stack unwinding.
 
Quindi, per come la intendo io, il codice per andare a cercare
l'exception handler opportuno non ha bisogno di essere generato, e
nemmeno il codice per andare a fare stack unwinding correttamente.
L'unica cosa che puo' accadere e' andare verso la terminazione diretta.


 L'unica cosa che puo' accadere e' andare verso la terminazione diretta.
 
Chiarissimo, grazie.
 
  bye
	av.
 

 l'uso delle eccezioni e' tutto meno che goffo.
 
beh, ma se prendi solo un pezzo della frase citata ne alteri 
il senso : ho scritto che è goffo per funzioni TRIVIALI, 
ossia quelle da tre righe.
Praticamente triplica il numero di righe della funzione solo 
per scrivere try le parentesi catch e altre parentesi.
Non ho detto e non penso che sia goffo tour court, anzi, 
appena il codice è complesso di suo, le eccezioni 
snelliscono. E' questione di soglia di semplicità, in 
sostanza, per come la vedo io.
CCCP


 ossia quelle da tre righe.
 
Ma e' proprio questo su cui non sono d'accordo! :)
 
Per me qualcosa come 
 
int f(...) {
  obj o;
  if(g(&o, ...)) { // g non puo' piu' ritornare un valore, perche'
                   // il ritorno va usato per il bool
    o.do_something();
  } else {
    o.clean_status();
  }
}
 
e' molto piu' goffo di:
 
int f() {
    obj o = g(...);
    o.do_something()
}
 
 
Se poi cominciamo a considerare cose pure molto semplici tipo:
 
int f() {
  value *v = new value (...);
  value *u = new value (...);
  obj o;
 
  if(g(&o, v, u)) {
    o.do_something();
  } else {
    delete u;
    delete v;
    o.clean_status();
  }
}
 
che in realta' contiene un memory leak grosso come una cosa e quindi lo
scriviamo correttamente come (non e' testato... non so se mi sono perso
qualcosa):
 
int f() {
  obj o;
  value *u;
  value *v = create_value(...);
  if (v == null) {
    goto cs;
  }
  u = create_value(...);
  if(u == null) {
    goto destroy_v;
  }
 
  value *u = new value (...);
 
  if(g(&o, v, u)) {
    o.do_something();
  } else {
    goto destroy_u;
  }
 
  destroy_u:
    delete u;
  destroy_v:
    delete v;
  cs:
    o.clean_status();
}
 
Che invece si confronta con:
 
int f() {
  shared_prt<value> u = create_value();
  shared_prt<value> v = create_value(); 
  obj o = g(u, v);
  o.do_something();
}
 
// o.clean_status() e' correttamente eseguito nel distruttore
 
Io *fatico* a considerare tutto questo goffo. Parliamo di una funzione
con tre oggetti in croce, non e' "complicata", per me. E mi sembra molto
piu' elegante. 


 piu' elegante.
 
Si si, elegante è elegante, ma a me non sembra un esempio 
relativo a quel che dicevo.
Boh
ciao


On 09/27/12 23:39, Soviet_Mario wrote:> Il 27/09/2012 17:09, Enrico 
Franchi ha scritto:
 >> Soviet_Mario<Soviet...@CCCP.MIR>  wrote:
 >>
 >>> beh, ma se prendi solo un pezzo della frase citata ne alteri
 >>> il senso : ho scritto che è goffo per funzioni TRIVIALI,
 >>> ossia quelle da tre righe.
 >>
 >> Ma e' proprio questo su cui non sono d'accordo! :)
 
Quoto!
 
 
 
 > non lo è ... ma di nuovo vedo stralciata la gestione delle eccezioni.
 > Forse non intendevamo la stessa cosa, boh
 
Credo che questo sia il punto:
_ i codidi di errore ti costringono a gestire gli errori sempre e comunque;
_ le eccezioni ti costringono alla gestione solo laddove puoi fare 
qualcosa: nell'esempio sopra, se f(), nel caso do_somehting vada male, 
puo' tentare un'altra strada, avvisare l'utente, o altro, allora  ha 
senso che lo faccia e ci metti il try/catch; in caso contrario non fai 
nulla e lasci che l'errore si propaghi (come del resto faresti con i 
codici di errore, ma senza doverlo scrivere esplicitamente).
 
 
 
 > (inoltre il confronto che proponi non mi pare equo : chiaro che se uso
 > oggetti di uno strato a maggiore astrazione, come shared_ptr, il codice
 > si "tersifica" di per sé a prescindere dalle eccezioni.
 
E' quello che scrivevo in un messaggio precedente: eccezioni e RAII 
devono andare di pari passo. Altrimenti e' come avere i chiodi e pensare 
di piantarli a pugni.
Devi utilizzare Smart pointer ed oggetti equivalenti se non vuoi che la 
gestione delle eccezioni diventi un inferno (questo che tu la faccia o 
che tu metta la testa sotto la sabbia, lasciando memory leak e quant'altro).
Tra l'altro, a prescindere dalle eccezioni, trovo questo paradigma molto 
piu' comodo.
 
 
  bye
	av.

 av.


On 09/28/12 11:32, Soviet_Mario wrote:
 >> _ le eccezioni ti costringono alla gestione solo laddove puoi fare
 >> qualcosa: nell'esempio sopra, se f(), nel caso do_somehting vada male,
 >> puo' tentare un'altra strada, avvisare l'utente, o altro, allora ha
 >> senso che lo faccia e ci metti il try/catch; in caso contrario non fai
 >> nulla e lasci che l'errore si propaghi (come del resto faresti con i
 >> codici di errore, ma senza doverlo scrivere esplicitamente).
 >
 > questo secondo caso però ho il sospetto che a volte non sia molto più
 > utile di chiamare direttamente abort ed ahmen.
 > Nel senso che quanto più ci si allontana dal punto dell'errore tanto più
 > diventa difficile tentare soluzioni (o anche solo sapere esattamente
 > cosa era andato storto e dove).
 
Credo dipenda molto dall'ambito.
 
Faccio un esempio: in un editor di testi, lancio una ricerca e qui sorge 
un qualunque problema: accetto un messaggio che dica qualcosa tipo 
"Errore interno: ecc..."; non accetto che il programma si chiuda con i 
miei dati non salvati.
Tradotto in codice: un catch nella prima funzione che viene chiamata 
alla pressione del tasto mi risolve la cosa indipendentemente da tutto 
quello che c'e' dietro.
 
Poi in altri casi puo' essere buono il tuo "abort", ma non lo vedo come 
soluzione generale.
 
  bye
	av.

 di piantarli a pugni.
 
 
Esatto ancora.


 anche solo sapere esattamente cosa era andato storto e dove).
 
Non scherziamo, dai. Una cosa del genere e' vera se stai gestendo
software giocattolo oppure "i primi esempi" quando tutte le risorse a
disposizione sono di fatto memoria, che viene liberata correttamente.
 
La fuori nel mondo reale succedono un sacco di cose. Modifichi lo stato
dei database (e li in genere ti va quasi bene perche' le transazioni le
gestiscono loro), lavori con files (e qui devi capire come fare le cose:
la mia idea e' che se sto facendo una modifica e qualcosa va male vorrei
che lo stato del mondo fosse come se non l'avessi mai tentata: *poi*
riporto l'errore a casa.
 
Ma in generale pensa alle applicazioni che esistono: pensa ad un
qualunque tipo di server. Se qualcosa va male, al piu' puo' chiudere il
contatto con il client. E anche qui spesso e' meglio notificargli che le
cose sono andate male (che e' qualcosa di ben diverso dal morire
brutalmente e tranciargli di conseguenza la connessione). Non solo:
spesso il server sta gestendo *milioni* di client. Sarebbe sgradevole se
per un errore in un'operazione crollasse tutto.


 per un errore in un'operazione crollasse tutto.
 
Mi cospargo il capo di cenere :-\
Ho estrapolato indebitamente dall'esperienza limitata e 
dilettantesca di SW ad uso personale, con soluzioni 
effettivamente per niente accettabili o concepibili nei 
contesti più vincolanti e complessi che dici.
Chiedo venia
ciao
CCCP
