Exceptii
si tratarea lor
|
Aspecte teoretice
|
In
scrierea programelor trebuie sa se specifice tratarea erorilor ce pot apare
in cazul functionarii. Puteti citi despre cazuri la care erorile aparute
in timpul exploatarii au cauzat pierderi considerabile la Software
Horror Stories.
In
acest material vom examina:
-
ce sunt
exceptiile
-
cum sunt
tratate.
Notiunea
de exceptie
Erorile
apar datorita greselilor de programare, logica; exceptiile apar datorita
unor probleme aparute in timpul rularii ( depasire de memorie, date in
afara limitelor prescrise ).
Variantele
de tratare a
exceptiilor ar fi:
-
Abandonarea
programului
-
Informarea
utilizatorului si terminarea programului
-
Informarea
utilizatorului, astfel incat acesta sa ia masuri pentru continuarea programului
-
Actiuni
automate de corectare, fara a informa utilizatorul.
C++ ofera
o metoda integrata si sigura pentru tratarea exceptiilor predictibile ce
pot apare in timpul rularii programelor.
O exceptie
este un obiect
care este pasat din zona codului unde a aparut o eroare, secventei de tratare
a problemei, functie de tipul exceptiei
- transmiterea poate fi facuta prin valoare sau referinta.
Mecanismul
de tratare a exceptiilor
Blocuri
try
sunt
create pentru a include codul unde pot apare probleme:
try
{
//
cod sau apel functie
.....
FunctieProbleme();
.....
}
Semnalarea
exceptiilor in blocurile try
se face prin instructiunea throw,
care trebuie executata in interiorul blocului try
sau intr-o functie apelata din bloc;
throw exceptie;
Blocuri
catch
trateaza
exceptiile semnalate de blocurile try,
urmandu-le pe acestea - la semnalarea unei exceptii intr-un bloc try
se
trece la blocul catch ce-l
urmeaza; daca pentru o exceptie lansata nu exista un bloc catch
aplicabil,
poate sa apara o terminare anormala a programului.
try
{
FunctieProbleme();
}
catch(OutOfMemory)
{
//
actiuni specifice
}
catch(FileNotFound)
{
//
alte actiuni specifice
}
Un
bloc catch
poate avea si forma:
catch(...)
{
//
tratare exceptie de orice tip
}
ce
apare in general dupa celelalte, tratand exceptiile ce nu au fost specificate
de acestea.
Pasii
pentru tratarea exceptiilor sunt:
-
identificarea
zonelor de cod unde ar putea apare exceptii si includerea lor in blocuri
try
-
crearea
de blocuri catch pentru
tratarea exceptiilor semnalate.
Relansarea
unei exceptii
O exceptie
poate fi relansata, dintr-un catch,
prin throw.
Aceasta
face ca exceptia curenta sa fie retransmisa unei secvente try/catch
exterioare. Motivul retransmiterii este sa se permita mai multor manipulatori
catch,
accesul la aceleasi exceptii. La relansare, o exceptie nu va fi preluata
de aceeasi instructiune catch, ci se va deplasa spre urmatoarea. A se vedea
exemplul 3.
Exemple
|
1.Iata
un prim exemplu simplu care semnaleaza o exceptie de tip intreg. La executie
sa se observe faptul ca dupa semnalarea erorii prin throw,
instructiile care urmeaza in blocul try
nu se mai executa, controlul fiind predat blocului catch.
Iesirea
programului va fi:
Intrare
in main
Intrare
in blocul try
Exceptia
tratata este:10
Terminare
main
| #include <iostream.h>
int main(){
cout<<"Intrare in main"<<endl;
try{
cout<<"Intrare in
blocul try"<<endl;
throw 10; //lansare
exceptie, se preda controlul blocului catch
cout<<"Instructiune
dupa throw"<<endl; //nu
se va tipari
} //terminare
bloc try
catch (int e){ //linie
marcata
cout<<"Exceptia
tratata este:"<<e<<endl;
}
cout<<"Terminare main"<<endl;
return 0;
} |
Daca
linia
marcata se inlocuieste cu:
catch (float e){
programul
se va termina anormal, din cauza ca exceptia de tip intreg semnalata in
try,
nu gaseste un bloc catch
pentru tratare.
2.Programul
de mai sus se modifica, astfel incat semnalarea exceptiei se face intr-o
functie apelata in blocul try:
Iesirea
programului va fi:
Intrare
in main
Intrare
in blocul try
Intrare
in functie cu valoarea:-4
Exceptia
tratata este:-4
Intrare
in functie cu valoarea:0
In
functie dupa throw
Intrare
in functie cu valoarea:10
Exceptia
tratata este:10
Terminare
try
Terminare
main
| #include <iostream.h>
void functie(int i){
cout<<"Intrare in functie cu
valoarea:"<<i<<endl;
if(i)throw i;
cout<<"In functie dupa throw"<<endl;
//nu
se va tipari daca se semnaleaza exceptie
}
int main(){
cout<<"Intrare in main"<<endl;
try{
cout<<"Intrare in
blocul try"<<endl;
functie(-4);
functie(0);
functie(10);
cout<<"Terminare
try"<<endl;
} //terminare
bloc try
catch (int e){
cout<<"Exceptia
tratata este:"<<e<<endl;
}
cout<<"Terminare main"<<endl;
return 0;
} |
3.In
programul de mai jos se relanseaza o exceptie de tip char*.
Iesirea
programului va fi:
Intrare
in main
Intrare
in blocul try din main
Intrare
in blocul try din functie
Tratare
exceptie curs C/C++ din catch interior
Intrare
in blocul try din functie
Tratare
exceptie 2002 din catch interior
Exceptia
tratata este:2002
Terminare
main
Sa
se elimine if din linia de relansare si sa se studieze functionarea programului
in acest caz; dar daca se comenteze linia?
#include <iostream.h>
#include <string.h>
void functie(char *s){
try{
cout<<"Intrare in
try din functie"<<endl;
throw s;
}
catch{
cout<<"Tratare exceptie
"<<s<<" din catch interior"<<endl;
if(strlen(s)<=4)throw;
//
se relanseaza exceptia daca sirul are lungimea <=4 //
linie marcata
}
}
int main(){
cout<<"Intrare in main"<<endl;
try{
cout<<"Intrare in
blocul try din main"<<endl;
functie("curs C/C++");
functie("2002");
functie("ianuarie"); //nu
se va apela
cout<<"Terminare
try"<<endl; //nu
se ajunge aici
} //terminare
bloc try
catch (char *sir){
cout<<"Exceptia
tratata este:"<<sir<<endl;
}
cout<<"Terminare main"<<endl;
return 0;
} |
4.In
programul de mai jos se defineste clasa Array; se semnaleaza exceptii,
obiecte ale clasei vide xBoundary
daca indicii sunt in afara domeniului.
De
fapt, pentru clasa xBoundary,
compilatorul creaza implicit constructor, destructor, copy constructor,
copy operator.
A se
observa definirea constructorului de copiere, a operatorului de copiere
=, dubla supraincarcare pentru operatorul de indexare [] - pentru cazul
cand se citeste sau se modifica valoarea unui element de tablou si supraincarea
operatorului de iesire << ( declarat ca si functie friend
).
La
rulare se va observa ca dupa initializarea elementelor tabloului ( indicii
intre 0 si 19 ), pentru indicele 20 se semnaleaza exceptie, tratata in
catch,
dupa care se iese din main.
Se
poate modifica programul astfel incat el sa semnaleze exceptie pentru toti
indicii intre 20 si 29?
| #include
<iostream.h>
const
int DefaultSize = 10;
class
Array
{
private:
int *pType; //adresa
tabloului
int itsSize; //numar
elemente
public:
// constructori
Array(int itsSize = DefaultSize);
Array(const Array &An_Array); //tabloul
se construieste ca fiind copia celui parametru
~Array() { delete [] pType;}
// operatori
Array& operator=(const Array&);
int& operator[](int offSet);
const int& operator[](int offSet) const;
// metode
int GetitsSize() const { return itsSize; }
// functie
friend
friend ostream& operator<< (ostream&, const Array&);
// se
defineste clasa xBoundary
( vida ) -obiectele ei vor fi exceptii
class xBoundary {};
};
Array::Array(int
size):itsSize(size){
pType = new int[size];
for (int i = 0; i<size; i++)
pType[i] = 0; //se
initializeaza elementele cu 0
}
Array&
Array::operator=(const Array &An_Array){
if (this == &An_Array)
return *this;
delete [] pType;
itsSize = An_Array.GetitsSize();
pType = new int[itsSize];
for (int i = 0; i<itsSize; i++)
pType[i] = An_Array[i];
return *this;
}
Array::Array(const
Array &An_Array){
itsSize = An_Array.GetitsSize();
pType = new int[itsSize];
for (int i = 0; i<itsSize; i++)
pType[i] = An_Array[i];
}
int&
Array::operator[](int offSet){
int size = GetitsSize();
if (offSet >= 0 && offSet < GetitsSize())
return pType[offSet];
throw xBoundary();
return pType[0]; //
nu se ajunge aici, se face return doar pentru a nu apare eroare in compilare
}
const
int& Array::operator[](int offSet) const{
int mysize = GetitsSize();
if (offSet >= 0 && offSet < GetitsSize())
return pType[offSet];
throw xBoundary();
return pType[0]; //
nu se ajunge aici, se face return doar pentru a nu apare eroare in compilare
}
ostream&
operator<< (ostream& output, const Array& theArray){
for (int i = 0; i<theArray.GetitsSize(); i++)
output << "[" << i << "] " << theArray[i] <<
endl;
return output;
}
int
main(){
Array intArray(20);
try{
for (int j = 0; j< 30; j++){
intArray[j] = j;
cout << "intArray[" << j << "] initializat" <<
endl;
}
}
catch (Array::xBoundary){
cout << "Indice eronat!\n";
}
cout << "Terminare main\n";
return 0;
} |

Exercitii
|
1.Scrieti
un program care citeste repetat intregi pana la introducerea valorii 0.
Intregii se vor citi ca siruri de caractere, semnalandu-se exceptii la
valori in afara domeniului int si la tastarea caracterelor invalide.
2.Se
cere sa se defineasca o clasa Queue care modeleaza functionarea unei cozi
( lista FIFO ) cu elemente de tip char. Dimensiunea cozii este limitata
si se specifica la creare - se semnaleaza exceptie in constructor daca
dimensiunea este <=0. Operatiile care se pot aplica asupra cozii sunt:
-
void Put(char)
- pentru introducerea caracterului parametru - se semnaleaza exceptie cand
coada e plina
-
char Get()
- pentru extragerea caracterului de la inceputul cozii - se semnaleaza
exceptie cand coada e goala.
Copyright
© 2001-2002. Carmen Holotescu
All
rights reserved. Published by Timsoft
|