-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
105 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
## TRATAREA EXCEPTIILOR | ||
Exceptiile sunt niste situatii deosebite ce pot aparea pe parcursul executiei unei aplicatii. Exista exceptii **sincrone** si exceptii **asincrone**. | ||
Exceptiile sincrone sunt usor de detectat: impartire prin 0, un fisier nu a putut fi deschis, etc. | ||
Exceptiile asincrone sunt mult mai greu de detectat si de tratat. | ||
Exceptiile sunt in general erori ce pot aparea in timpul functionarii unui program. O data detectate, exceptiile trebuie tratate. | ||
Exemple de masuri: | ||
- se afiseaza mesaje pe ecran sau in log | ||
- se reincearca executia unei secvente de program sau se reporneste executia | ||
In limbajul C, tratarea exceptiilor poate fi facuta cu ajutorul unor functii din fisierul antet ```setjmp.h```. Pentru tratarea exceptiilor avem nevoie de tipuri de date ```jmp_buf```, functia ```setjmp``` si functia ```longjmp```. | ||
Intr-o variabila de tip ```jmp_buf``` poate fi incarcata starea programului din momentul apelului functiei ```setjmp```. Prin starea programului intelegem stiva de executie a aplicatiei. La primul apel al functiei ```setjmp```, functia returneaza valoarea ```0```. Cu ajutorul functiei ```longjmp``` ne putem intoarce la linia in care ```setjmp``` a salvat starea executiei, moment in care se reincarca starea executiei salvata. Cu alte cuvinte, apelul ```longjmp``` este echivalent cu incarcarea stivei de executie dintr-o variabila ```jmp_buf``` si un ```goto``` la linia in care ```setjmp``` a salvat starea programului. Cu ajutorul acestor doua functii este simulata functionalitatea unei instructiuni de tipul ```try catch``` impreuna cu ```throw```, care nu exista in C. | ||
|
||
```cpp | ||
jmp_buf stare; | ||
float div(float x, float y) | ||
{ | ||
if(!y) | ||
long_jmp(stare,1); // throw | ||
else | ||
return x/y; | ||
} | ||
|
||
void main() | ||
{ | ||
float a,b; | ||
cin>>a>>b; | ||
if(!setjmp(stare)) | ||
{ | ||
cout<<"Impartire = "<< div(a,b) << endl; | ||
} | ||
else | ||
{ | ||
cerr<"Exceptie"<<endl; | ||
} | ||
} | ||
``` | ||
La executie, cand se ajunge prima oara la functia ```setjmp``` este salvata starea programului. Functie ```setjmp``` returneaza ```0``` inseamna ca se trece la afisarea cu ```cout```. Daca in functia ```div``` apelata, al doilea parametru are valoarea ```0``` executia se incheie in functia ```div``` , se incarca starea salvata si se face un salt la linia in care este apelata ```setjmp```. La al doilea apel al functiei ```setjmp``` este returnata valoarea ```1``` si executia continua pe ramura ```else``` cu mesajul de eroare. | ||
In limbajul C++ putem trata exceptiile cu ajutorul functiilor mostenite din C, dar, in C++ au fost introduse doua instructiuni pentru tratatea exceptiilor: ```throw``` si ```try ... catch``` . La detectarea unei exceptii, instructiunea ```throw``` intrerupe executia si *arunca* o valoare ce este captata in functie de tipul ei pe una dintre ramurile ```catch``` daca exceptia a aparut in blocul ```try```. | ||
Vrem sa calculam ```loga(b)```: | ||
```cpp | ||
double logaritm(double x, double y) // logx(y) | ||
{ | ||
if(x<=0) | ||
throw 1; | ||
if(y<=0) | ||
throw 2; | ||
if(x==1) | ||
throw "Baza nu poate fi 1."; | ||
return log (y) / log (x); | ||
} | ||
void main() | ||
{ | ||
double a,b; | ||
cin>>a>>b; | ||
try | ||
{ | ||
cout<<"log = "<<logaritm(a,b)<<endl; | ||
} | ||
catch(int v) | ||
{ | ||
if(v==1) | ||
cerr<< "Baza nu este pozitiva."; | ||
if(v==2) | ||
cerr<< "Argumentul nu este pozitiv"; | ||
} | ||
catch(const char* msg) | ||
{ | ||
cerr<<msg<<endl; | ||
} | ||
catch(...) | ||
{ | ||
cerr<< "Alta eroare"<<endl; | ||
} | ||
} | ||
``` | ||
Dupa citirea valorilor ```a``` si ```b``` se incearca executia codului din blocul ```try```. Daca nu au aparut exceptii (aruncate cu o instructiune ```throw```), mesajul este trimis in ```cout``` (pe ecran). Daca in blocul ```try``` apare o exceptie, executia se incheie, mesajul neafisandu-se, iar executia continua pe una dintre ramurile ```catch```. Daca ```x<=0``` sau ```y<=0``` atunci este aruncata o valoare de tip ```int```, (1 sau 2), in consecinta executia este intrerupta si se revine la prima instructiune ```try...catch```, unde executia continua pe ramura ```catch``` cu parametru ```int```, deoarece valoarea aruncata este de tipul ```int``` (1 sau 2). Daca ```x=1``` executia se incheie *aruncandu-se* un mesaj, practic, aruncandu-se adresa de memorie a mesajului respectiv. Executia continua in aceasta situatie pe ramura ```catch``` cu valoare ```const char*```, unde se primeste adresa de memorie a textului aruncat. | ||
In functie de tipul valorii aruncate de o instructiune ```throw``` si de tipurile de date ale ramurilor ```catch``` se incearca potrivirea cea mai buna. (```short int``` -> ```int```, ```int``` -> ```float```). Daca valoarea aruncata nu poate fi convertita la niciunul din tipurile ramurilor catch, executia continua pe ramura ```catch(...)``` , daca exista, unde este tratata sau exceptia ramane netratata, rezultand eroare la executie: ```Unhandled exception.```. | ||
Exista, in functie de compilator, si alte posibile ramuri ale instructiunii ```try...catch```. De exemplu, Visual C++ putem sa avem ramuri de tip ```except``` sau ```final```, dar nu sunt standard. In Java exista ```final``` standard. | ||
Instructiunea ```throw``` poate fi apelata fara valoare. La intalnirea unui ```throw``` fara valoare, daca exista o valoare aruncata si inca netratata, ea este aruncata pentru a fi tratata in urmatoarea instructiune ```try...catch```. | ||
```cpp | ||
float a,b; | ||
cin>>a>>b; | ||
try | ||
{ | ||
try | ||
{ | ||
if(!b) | ||
throw 0; | ||
cout<<a<<b<<endl; | ||
} | ||
catch(int v) | ||
{ | ||
cerr<< "Eroare"<<endl; | ||
throw; | ||
} | ||
} | ||
catch(int v) | ||
{ | ||
cerr<< "Impartire la 0."<<endl; | ||
} | ||
``` | ||
La a doua instructiune ```try...catch```, daca se intalneste situatia ```b=0``` se decide ca exceptia sa nu fie tratata aici, aruncandu-se tratarea ei intr-o instrunctiune ```try...catch``` de mai sus, adica, pe ramura ```catch``` a primei instructiuni ```try...catch```. *Aruncarea* tratarii pe un nivel superior se face cu ```throw;```. | ||
Desi tratarea exceptiilor cu ajutorul instructiunilor ```try...catch``` este moderna si eleganta, codul din corpul ```try``` se executa mai incet, comparativ cu situatia in care nu ar fi introdus intr-un astfel de corp. De aceea, folosirea instructiunilor ```try...catch``` este preferabil de a fi editata, acolo unde avem nevoie de viteza mare de executie. | ||
Foarte multi programatori de C++ evita complet utilizarea instructiunilor ```try...catch```. | ||
In momentul in care se scrie o aplicatie cu tratare de exceptii se prefera scrierea de clase speciale pentru exceptii, chiar ierarhii. Intr-u obiect de tip exceptie se memoreaza detalii despre exceptia respectiva in mai multe campuri. In alte limbaje, precum Java, aceasta practica este absolut fireasca tocmai din cauza ca Java se doreste a fi un limbaj sigur. |