Document, comentariu, eseu, bacalaureat, liceu si facultate
Top documenteAdmitereTesteUtileContact
      
    


 


Ultimele referate adaugate

Adauga referat - poti sa ne ajuti cu un referat?

Politica de confidentialitate



Ultimele referate descarcare de pe site
  CREDITUL IPOTECAR PENTRU INVESTITII IMOBILIARE (economie)
  Comertul cu amanuntul (economie)
  IDENTIFICAREA CRIMINALISTICA (drept)
  Mecanismul motor, Biela, organe mobile proiect (diverse)
  O scrisoare pierduta (romana)
  O scrisoare pierduta (romana)
  Ion DRUTA (romana)
  COMPORTAMENT PROSOCIAL-COMPORTAMENT ANTISOCIAL (psihologie)
  COMPORTAMENT PROSOCIAL-COMPORTAMENT ANTISOCIAL (psihologie)
  Starea civila (geografie)
 

Ultimele referate cautate in site
   domnisoara hus
   legume
    istoria unui galban
   metanol
   recapitulare
   profitul
   caract
   comentariu liric
   radiolocatia
   praslea cel voinic si merele da aur
 
despre:
 
Tratarea exceptiilor in C++
Colt dreapta
Vizite: ? Nota: ? Ce reprezinta? Intrebari si raspunsuri
 

Tratarea exceptiilor permite rezolvarea in mod unitar a erorilor de executie. Mecanismul de tratare a exceptiilor din C++ ofera posibilitatea ca o problema care apare intr-o functie si aceasta nu o poate rezolva, sa fie definita ca o exceptie, cu speranta ca functia apelanta va trata aceasta problema. O functie care doreste sa trateze astfel de probleme va indica acest lucru prin captarea exceptiei respective, iar codul care se executa la captare se numeste rutina de tratare a exceptiei (exception handler). l9t20tp
Ca exemplu, se considera modul in care poate fi tratata o depasire de dimensiune in clasa Vector.

class VectorA int* p; int sz; public: class Range AS; // exceptie la depasire dimens. int& operatorai(int i);
// ....
S; int& Vector::operatorai(int i)A if (0 <= i && i < sz) return paii; throw Range(); return pa0i; // numai pt. evitare erori comp.
S void f(Vector &v)A try A fv(v); // apelul unei functii
S catch(Vector::Range)A
// Rutina de tratare a exceptiei
// Vector::Range
// In acest punct se ajunge numai daca
// in functia fv(v) s-a apelat operatorul ai
// cu un indice in afara domeniului
S
S

Constructia:

catch ( /*…..…… */)A
// …….
S

este numita rutina de tratare a exceptiei (exception handler). Ea este apelata imediat dupa un bloc prefixat de cuvantul cheie try sau dupa o alta rutina de tratare a unei exceptii. Paranteza care urmeaza cuvantului cheie catch contine o declaratie care este folosita ca un argument: aceasta declaratie specifica tipul exceptiei de care se ocupa rutina de tratare a erorii si, uneori, numele argumentului.
Daca o exceptie (ceea ce insemna o eroare) apare intr-un bloc prefixat de specificatorul try, ea este lansata de catre instructiunea throw, dupa care este captata intr-o rutina de tratare a exceptiilor (deci in blocul instructiunii catch) si prelucrata. Blocul try trebuie sa contina acea sectiune a programului in care se doreste sa fie cautate erorile. El poate cuprinde cateva instructiuni intr-o functie sau chiar intregul corp al functiei main(), ceea ce inseamna urmarirea erorilor in intregul program.
Atunci cand o functie genereaza o exceptie, ea nu isi mai continua executia ca in situatia in care ar apela o functie de tratare a erorii, din care se revine printr-o instructiune return, ci executia este captata in rutina de tratare, dupa care se continua programul cu instructiunile care urmeaza rutinei de tratare a exceptiei.




8.1 Discriminarea exceptiilor

In mod obisnuit, intr-un program pot apare mai multe tipuri de erori de executie (run-time errors) si fiecare tip de eroare poate fi asociat unei exceptii cu un nume distinct. Captarea exceptiilor este executata de mai multe blocuri catch, care pot fi asociate unuia sau mai multor blocuri try. Forma generala pentru un bloc try urmat de mai multe blocuri catch care trateaza diferite tipuri de exceptii este urmatoarea: try A
// bloc try
S catch (tip_arg1 arg1) A
// bloc de tratare a exceptiei
// de tipul tip_arg1
S catch (tip_arg2 arg2) A
// bloc catch de tratare a exceptiei
// de tipul tip_arg2
S
………………………………….

catch (tip_argn argn) A
// bloc de tratare a exceptiei
// de tipul tip_argn
S

O astfel de constructie este asemanatoare unei instructiuni switch, in care selectia unei rutine (un bloc catch) se face in functie de tipul exceptiei lansate in blocul try, fara sa fie necesara o instructiune break. Daca in blocul try nu apare nici o exceptie, toate blocurile catch consecutive acestuia sunt ignorate. La aparitia unei exceptii, controlul programului este transferat rutinei de tratare a exceptiei corespunzatoare tipului acesteia, toate celelate blocuri catch fiind ignorate. Dupa executia unei rutine de tratare a exceptiei, programul fie continua cu executia instructiunilor urmatoare blocurilor catch, fie se termina, daca rutina respectiva a apelat o functie exit() sau abort().
Daca se lanseazeaza o exceptie pentru care nu exista nici o rutina de tratare (bloc catch), atunci este posibil sa apara o executie anormala a programului.

? Exemplul 8.1

void fd()A char tip;
while (tip !='q')A tryA int argi; double argd; char argc; cout << “Start bloc try\n”; cout << "Introduceti tipul si argumentul exceptiei: "; cin >> tip; switch (tip)A case 'i': cin >> argi; cout << "Lansare exceptie int\n"; throw argi; break; case 'd': cin >> argd; cout<<"Lansare except. double\n"; throw argd; break; case 'c': cin >> argc; cout<<"Lansare exceptie char\n"; cout.flush(); throw argc; break;
S cout << "Nu s-a lansat exceptie\n";
S catch(int i)A cout << "Captare exceptie int i = " << i <<endl;
S catch(double d)A cout << "Captare exceptie double d = " << d <<endl;
S cout << "End bloc try-catch\n";
S
S

In aceasta functie se poate selecta tipul si argumentul unei exceptii prin valori introduse de la consola. La selectia tipului de argument int (prin introducerea de la tastatura a caracterului i), se lanseaza o exceptie pentru tipul de date integer, cu o valoare a argumentului egala cu valoarea citita de la consola. Aceasta exceptie este captata de instructiunea catch(int i), care primeste in argumentul i valoarea cu care a fost lansata exceptia de tip integer si o afiseaza.
Cu acest program se pot testa diferitele situatii care pot apare in executia blocurilor try-catch: selectarea uneia din rutinele de tratare a exceptiilor (unul din blocurile catch) in functie de tipul exceptiei lansate in blocul try, ignorarea tuturor blocurilor catch daca in blocul try nu se lanseaza nici o exceptie, precum si terminarea anormala a programului in situatia in care s-a lansat o exceptie, dar nu exista o rutina de tratare pentru tipul exceptiei lansate.
Liniile de afisare care se pot obtine la executia functiei fd(), pentru diferite situatii selectate, sunt prezentate mai jos:

Start bloc try
Introduceti tipul si argumentul exceptiei: i 2
Lansare exceptie int
Captare exceptie int i = 2
End bloc try-catch

Start bloc try
Introduceti tipul si argumentul exceptiei: d 3.5
Lansare exceptie double
Captare exceptie double d = 3.5
End bloc try-catch

Start bloc try
Introduceti tipul si argumentul exceptiei: g
Nu s-a lansat exceptie
End bloc try-catch

Start bloc try
Introduceti tipul si argumentul exceptiei: c a
Lansare exceptie char

Abnormal program termination

?


In mod asemanator, in clasa Vector pot fi tratate mai multe tipuri de erori: in afara de eroarea de depasire a dimensiunii vectorului, poate fi tratata si eroarea care apare datorita unei valori inacceptabile la constructia vectorului:

class VectorA int* p; int sz; enum Amax=1000S; public: class Range AS; // exceptie la depasire domeniu class Size AS; // exceptie la constructie
Vector(int s); int& operatorai(int i);

// ....
S;
Vector::Vector(int s)A if (s < 0 || max < s) throw Size(); sz = s; p = new intasi;
S

Asa cum s-a aratat mai sus, operatorul de indexare ai al clasei Vector va lansa exceptia de tip (clasa) Range daca este apelat cu un indice in afara domeniului. In mod similar, constructorul Vector::Vector va lansa o exceptie de tip Size, daca este apelat cu un argument cu o valoare inacceptabila.
In utilizarea clasei Vector se poate discrimina intre cele doua exceptii prin adaugarea a doua rutine de tratare a exceptiilor dupa un bloc try:

void fex(Vector &v)A try A fv(v); // apelul unei functii cu arg. v
S catch(Vector::Range)A
// Rutina de tratare a exceptiei
// Vector::Range
// In acest punct se ajunge numai daca
// in functia fv(v) s-a apelat operatorul ai
// cu un indice in afara domeniului
S catch(Vector::Size)A
// Rutina de tratare a exceptiei
// Vector::Range
// In acest punct se ajunge daca in functia
// fv(v) s-a apelat un constructor
// cu un argument cu o valoare inacceptabila
S
S

8.2 Modalitati de tratare a exceptiilor

In C++ exista multe modalitati de tratare a exceptiilor, dintre care o parte vor fi descrise in continuare.

8.2.1 Tratarea tuturor exceptiilor

In Exemplul 8.1 a fost prezentata o situatie in care nu era tratata o exceptie de un anumit tip, situatie care provoaca executia anormala a programului, atunci cand o astfel de exceptie este lansata in blocul try corespunzator. Acstfel de erori pot fi evitate daca se foloseste o constructie de captare a tuturor erorilor, care are urmatoarea sintaxa:

catch(…)A
// tratare generala exceptii
S

Instructiunea catch(…) indica captarea oricaror exceptii (corespunzatoare tuturor tipurilor de date). Tratarea exceptiilor in astfel de situatii poate fi o tratare generala.
Mai este posibila combinarea uneia sau mai multor instructiuni catch de captare a unor tipuri specifice de exceptii cu o instructiune de captare a tuturor exceptiilor, combinatie prin care se urmareste tratarea diferentiata a unor anumite tipuri de exceptii, toate celelalte fiind tratate global. Astfel de constructii permit evitarea terminarii anormale a programului.
Daca in functia fd() din Exemplul 8.1 se adauga dupa blocul try o instructiune catch(…) de captare generala, atunci nu mai apare eroarea de executie la lansarea unei exceptii netratate specific:

//………………………….. tryA
// acelasi bloc ca in Exemplul 8.1
S catch(int i)A cout << "Captare exceptie int i = " << i <<endl;
S catch(double d)A cout << "Captare exceptie double d = " << d <<endl;
S catch(…)A cout << "Captare exceptie oarecare\n”;
S
//…………………………….

La lansarea exceptiei cu argument de tip caracter (throw argc) se transfera controlul rutinei de captare generala a exceptiilor (care, in exemplul de mai sus afiseaza doar un mesaj la consola) si nu mai apare executia anormala a programului.

8.2.2 Transferul de informatii catre rutina de tratare a exceptiei

O exceptie poate fi captata prin specificarea tipului ei. Totusi, ceea ce se lanseaza (throw) in momentul aparitiei unei erori nu este un tip de date ci un obiect de tipul respectiv, care este construit la apartia erorii. De aceea, in definirea unui tip exceptie (clasa) se pot adauga date membre care pot fi setate la constructia obiectului lansat si utilizate in rutina de tratare a exceptiilor pentru a identificarea conditiilor de aparitie a erorii.

De exemplu, clasa Range de definire a exceptiei de depasire a dimensiunii vectorului poate sa contina o data membra index care memoreaza valoarea indicelui care a produs depasirea si o functie publica getindex() care permite citirea acestei valori, astfel incat valoarea indicelui care a produs depasirea poate fi aflat si, eventual, afisat in rutina de tratare a erorii. La fel se poate proceda si pentru clasa Size. Exemplul urmator completeaza clasa Vector si clasele exceptie definite de aceasta si ilustreaza crearea si utilizarea obiectelor de clasa execptie.

? Exemplul 8.2

In clasa Vector sunt definite clasele exceptie Range si Size care permit stocarea si regasirea unor informatii prin intermediul obiectelor lansate la aparitia unei erori de un anumit tip. La apelul unei functii operator de indexare ai a clasei Vector cu o valoare a indicelui i < 0 sau i >= sz, se lanseaza exceptia de depasire a domeniului prin construirea unui obiect din clasa Range, cu argumentul i: Range(i). Obiectul lansat memoreaza (prin constructie) aceasta valoare. Rutina de tratare a exceptiei de depasire a domeniului are ca argument un obiect r de clasa Vector::Range, care este chiar obiectul lansat la aparitia erorii in functia operator de indexare. Folosind functiile membre ale acestui obiect, rutina de tratare a exceptiei poate regasi informatii privind conditia de aparitie a erorii.

class VectorA int* p; int sz; enum Amax=1000S; public:
Vector(int s); class Range A // clasa exceptie int index; public:
Range(int i)Aindex = i;S int getindex()Areturn index;S
S; class Size A // clasa exceptie int dim; public:
Size(int d)Adim=d;S int getdim() Areturn dim;S
S;

int& operatorai(int i); int getsize() Areturn sz;S
// ....
S;
Vector::Vector(int s)A if (s < 0 || max < s) throw Size(s); sz = s; p = new intasi;
S int& Vector::operatorai(int i)A if (0 <= i && i < sz) return paii; throw Range(i); return pa0i; // numai pentru evitarea erorii
// de compilare
S void fv(Vector& v, int d)A
Vector v2(d); for (int i=0;i<d;i++)A v2aii = vaii = i;
S
S void fex(Vector &v, int d)A tryA fv(v, d);
S catch(Vector::Range r)A cerr << "Indicele " << r.getindex()
<< " in afara domeniului\n"; return;
S catch(Vector::Size s)A cerr << "Dimensiunea " << s.getdim()
<< " depaseste valoarea admisa\n"; return;
S cout << "Vectori OK" << endl; return 0;
S

void main()A
Vector v1(100); int d; cout << "Introduceti dimensiunea: "; cin >> d;

while(fex(v1,d))A cout << "Introduceti dimensiunea: "; cin >> d;
S
S

La executia acestui program se creaza mai intai un vector de dimensiune 100, dupa care se citeste de la tastatura dimensiunea unui alt vector. In functie de valoarea introdusa la consola, pot apare trei situatii distincte.
Daca dimensiunea introdusa d este mai mica sau egala cu dimensiunea primului vector (100), atunci nu apare nici-o eroare de executie, programul afiseaza un mesaj la consola dupa care se opreste.
Daca dimensiunea introdusa d este mai mare decat dimensiunea primul vector (100), dar mai mica decat valoarea maxim admisibila pentru constructia vectorilor (max=1000), atunci apare o eroare de depasire a domeniului in functia operator de indexare ai si se lanseaza exceptia prin construirea unui obiect de clasa Range, cu argument al constructorului egal cu valoarea primului indice care depaseste domeniul. Aceasta valoare este regasita in functia de tratare a exceptiei, care o afiseaza la consola. Mesajele care apar la consola in aceasta situatie sunt:

Introduceti dimensiunea: 200
Indice 100 in afara domeniului
Introduceti valoarea:

Daca dimensiunea introdusa d este mai mare decat valoarea maxima admisibila (1000), atunci apare o eroare in momentul constructiei obiectului v2 de tip Vector in functia fex(). In constructorul Vector::Vector, la aparitia unei astfel de erori se lanseaza o exceptie prin construirea unui obiect de tip Size, cu valoare a argumentului d, valoare care este memorata in data membra privata dim a clasei Size. Aceasta valoare este regasita in functia de tratare a exceptiei, care o afiseaza la consola. Mesajele care apar la consola in aceasta situatie sunt:

Introduceti dimensiunea: 1001

Dimensiunea 1001 depaseste valoarea admisa
Introduceti dimensiunea:

?
8.2.3 Imbricarea rutinelor de tratare a exceptiilor

Limbajul C++ admite constructii imbricate de tratare a execptiilor, ca de exemplu:

tryA
// bloc try
S catch (ExceptionX)A try A
// o rutina care incearca
// tratarea exceptiei
S catch(ExceptionX)A
// o alta rutina de tratare
// care este lansata daca prima rutina
// a provocat o noua exceptie
S
S

O exceptie este tratata de rutina imediat urmatoare blocului try, dar si in aceasta tratare poate fi lansata o noua exceptie (eventual de acelasi tip), de care se va ocupa un nou bloc catch, imbricat in primul bloc try. Desi posibile, astfel de constructii imbricate sunt rar utilizate sau utile.

8.2.4 Gruparea exceptiilor

De cele mai multe ori, exceptiile se pot grupa in familii, in functie de categoria la care se refera. De exemplu, erori de depasire superioara, depasire inferioara de impartire la zero si altele pot fi grupate in categoria de erori in operatii aritmetice cu numere flotante; erori de deschidere fisier, inchidere fisier, erori de citire sau erori de scrire, pot fi grupate ca erori in operatii cu fisiere, s.a.md.
In astfel de situatii, rutinele de tratare a exceptiilor sunt destul de asemanatoare si se pot implementa intr-un mod unitar. Implementarea unitara a grupurilor de exceptii se poate face in doua modalitati: prin enumerare si prin organizarea exceptiilor in ierarhii de clase folosind mostenirea si functiile virtuale.
In abordarea prin enumerare a grupurilor de exceptii se defineste un tip enumerare ale carui posibile valori sunt numele tuturor exceptiilor din grup, iar selectia intre rutinele specifice se face printr-o instructiune switch:

class Overflow A S; class Underflow A S; class Dividebyzero A S;

enum Mathenum AOverflow, Underflow, DividebyzeroS; void fenum()A tryA
// lansare exceptii
S catch (Mathenum m)A switch (m)A case Overflow:
// tratare depasire superioara break; case Underflow:
// tratare depasire inferiora break; case Dividebyzero:
// tratare impartire la 0 break;
S
S
S

O astfel de organizare a grupurilor de exceptii, desi posibila, este voluminoasa si cu mari riscuri de a a fi omise unele situatii, care, bineinteles, vor provoca terminarea anormala a programului. In plus, la adaugarea unei noi exceptii intr-un grup de exceptii ale unei biblioteci, ar fi necasara recompilarea tuturor modulelor care contin rutine de captare a exceptiilor. Acest lucru este, bineinteles, imposibil si de aceea ar fi preferabil sa nu se adauge noi exceptii intr-o biblioteca daca tratarea grupurilor de exceptii este implementata prin enumerarea acestora.
O solutie mai eleganta si mai robusta o reprezinta organizarea exceptiilor in ierarhii de clase. De exemplu:

class Matherr A S; class Overflow : public MatherrA S; class Underflow : public Matherr A S; class Dividebyzero : public Matherr A S;

void fder()A tryA
// lansare exceptii
S catch (Overflow)A
// tratare depasire superioara
S catch (Matherr)A
// tratare orice exceptie Matherr
// care nu este Overflow
S
S

In acest exemplu, dintre toate exceptiile care pot fi lansate in blocul try, exceptia Overflow are o tratare speciala, in timp ce toate celelalte exceptii derivate din clasa Matherr au o tratare globala prin rutina catch(Matherr), deci nu vor provoca terminarea anormala a programului.

Din exemplele prezentate pana acum se poate observa ca exceptiile pot fi definite global, pentru intregul program, cum sunt exceptiile Matherr sau Overflow, sau pot fi exceptii locale unei clase, cum sunt exceptiile Range sau Size, definite in clasa Vector. Pentru astfel de exceptii, in instructiunea catch trebuie sa fie specificat domeniul clasei exceptie: catch (Vector::Range).


Colt dreapta
Creeaza cont
Comentarii:

Nu ai gasit ce cautai? Crezi ca ceva ne lipseste? Lasa-ti comentariul si incercam sa te ajutam.
Esti satisfacut de calitarea acestui document, eseu, cometariu? Apreciem aprecierile voastre.

Nume (obligatoriu):

Email (obligatoriu, nu va fi publicat):

Site URL (optional):


Comentariile tale: (NO HTML)


Noteaza documentul:
In prezent fisierul este notat cu: ? (media unui numar de ? de note primite).

2345678910

 
Copyright© 2005 - 2024 | Trimite document | Harta site | Adauga in favorite
Colt dreapta