Kivételkezelés
A Wikipédiából, a szabad lexikonból.
Ezen szócikk összedolgozandó a(z) kivétel szócikkel, azután az egyik lap törlendő. |
A kivételkezelés egy, a számítógépek programozásában használatos módszer a várható és nem várható hibák és események észlelésére és a rájuk történő reagálásra.
A programok alapvetően szekvenciális - így a folyamatában jól nyomon követhető - működésében sok esetben következhetnek be olyan események, amelyekre a programozó nem készül, vagy nem készülhet fel (esetleg nem is akar felkészülni).
Az ilyen, általában hibajelenségek az alapvető utasításkészlettel régen nem voltak kezelhetőek/elkaphatóak.
Így a programozónak kellett sok olyan sorral megtűzdelnie a kódjait, amelyek nem csak a helyet foglalták, de ormótlanná tették és le is lassították a program futását. Ha nem tette volna meg ezt, akkor hiba esetén az alkalmazása váratlan helyen megszakította volna a futását, és ezáltal a program használata adatvesztéssel járt volna.
Nézzük konkrétan egy példát: egész értékké szeretnénk alakítani egy szövegfüzért. A hagyományos megoldás esetén két visszatérési értéket kell szolgáltatnunk: magát az eredményt, illetve egy változót, amellyel jelezzük, ha nem tudtuk végrehajtani a művelet (ezzel esetleg információt adunk arról is, hogy miért nem sikerült maga a konverzió).
Pszeudo-kód:
AzEgesz, AzEredmeny = Szoveget_Egessze(ASzoveg) Ha Sikeres ... Ha Nem Sikeres, miért is ? ...
Python-stílusú kód:
... an_int, an_rescode = str_to_int(a_string) if an_rescode == 1: print "Non numeric value" elif an_rescode == 2: print "Numeric value overflow" elif an_rescode == 0: print "The value is:", an_int ...
A kivételkezeléses módszernél két blokkot definiálunk. Az elsőben magát az egésszé alakító utasítást helyezzük el, a másodikban pedig a hiba előfordulásakor lefutó kódsort.
Pszeudo-kód:
Vizsgalando blokk: AzEgesz, AzEredmeny = Szoveget_Egessze(ASzoveg) # Sikeres, folytatjuk a többi kóddal ... Hibakezelo blokk: # Nem volt sikeres, hiba törtért, itt kezelhetjük ...
Python-stílusú kód:
... try: an_int=str_to_int(a_string) print "The value is:", an_int except: print "Value converting error" ...
Kezdetben a BASIC szintű nyelvek az
ON ERROR GOTO
utasítással valósították meg az olyan hibák elkapását, amelyekre maga a nyelv az egyéb utasításaival nem lett volna képes.
Hiba előfordulása esetén megszabhattuk a folytatás helyét a kódunkban, így kezelni tudtuk azt. Azaz a fenti példánál nem megfelelő numerikus szövegértéket kapván a kivételkezelő blokknál folytatódott a végrehajtás.
Később, az alacsonyabb szintű, például fordított (kompilált) programnyelveknél is megjelentek a hasonló szekvenciák - mindehhez pedig a hardverszintű támogatás adott lehetőséget.
A processzoroknál a megszakítások egy részét speciálisan, szoftveresen programozhatóra alakították ki. Ezeket például a kivételek részére tartják fenn.
Ha megnézzük, akkor jól látható a hasonlóság a kivételek és a megszakítások között.
A kivételek tulajdonképpen a programok tervszerű, vagy eseményektől függő megszakításai, melyeknél a kód futása egy előre definiált szakasznál (kódsor, memóriaszakasz) folytatódik.
A kivételek alapvetően kétféle fajtájúak:
- operációs rendszerszintű kivételek (pl. memória vagy erőforrás elfogyása, hibás memóriaterületről olvasás, vagy oda írás, stb.)
- programszintű kivételek (konverziós, eseményeket jelző, stb.).
A kompilált kódok esetében egy speciális kezelőt regisztrálunk az operációs rendszer számára.
E kód a veremben, vagy egyéb területen elhelyezett jelzők alapján fogja tudni kideríteni, hogy hol kell folytatódnia a kódnak kivétel történte esetén.
Interpretált nyelveknél ezeket a funkciókat az értelmező és futtató modul végzi.
A manapság használt nyelveknél általában kétféle kivételkezelő utasításblokkot találhatunk, amelyek szinonimák:
try {blokk} (on) except(ion) {hibakezelő blokk}
try {blokk} catch {hibakezelő blokk}
A fenti elemeket a megfelelő erőforráskezelés számára kiegészítették egy újjal - hiszen a program futása a kivételekre "várakozás" miatt nem várt irányba is folytatódhat, aminek okán az előzőleg lefoglalt erőforrások nem kerülnek felszabadításra - memóriafolyást, memóriahiányt okozva.
Ezért egy olyan blokkot is definiálhatunk, amelynek célja a mindenkoron - akár kivétel bekövetkezte esetén is - történő lefutás.
Ezt általában "finally" utasítással teszik. Használata:
try {blokk} except {hibakezelő blokk} finally {mindenképpen lefutó blokk}
Példa a hibás erőforráskezelésre:
try: afile=open_new_file("data.fil","w") afile.write(data) afile.close() except: print "Nem sikerült az adat mentése" # nincs lezárva a fájl és felszabadítva a hozzá tartozó memóriapuffer
Helyesen:
try: afile=None afile=open_new_file("data.fil","w") afile.write(data) except: print "Nem sikerült az adat mentése" finally: if afile<>None: afile.close()
Megjegyzés: több nyelvnél a "finally" taghoz tartozó kódblokk általában előbb fut le, mint az "except" szakasz.
Ezek tehát a kivételkezelés alapjai dióhéjban.