Výjimky umožňují v programu ošetřit množství chybových stavů. Chyba se může vytvořit během provádění programu. Například, když se program dotáže na zadání bodu v AutoCADu a uživatel stornuje akci výběru (tzn. nezadá žádný bod) je vygenerována chyba. C++ umožňuje takovéto chyby jednoduchým způsobem dynamicky detekovat a ošetřit. K detekci a ošetření chyb slouží v C++ tzv. správa chyb (exception handling).
Správa chyb je v C++ založena na koncepci předej a chyť (throw - and - catch). Throw - and - catch umožňuje metodě vrátit chybu pomocí příkazu throw, nebo ošetřit výskyt chyby pomocí příkazu catch.
try { pokusný_blok } catch (typ [identifikátor]) // musí navazovat na blok try { tělo_ošetření_výjimky }
pokusný_blok | |||
Blok příkazů, které potřebujeme kontrolovat na výskyt chyby (výjimky). | |||
typ | |||
Datový typ proměnné, která ponese informace o výjimce, často se označuje jako typ výjimky. Může být i reference. |
|||
identifikátor | |||
Identifikátor proměnné, která ponese informace o výjimce. Můžeme jej vynechat, ale pak nemůžeme objekt, který nese informace o výjimce v těle_ošetření použít. | |||
tělo_ošetření_výjimky | |||
Příkazy ošetřující výskyt výjimky. |
Nedojde-li k výskytu chyby (výjimky) v pokusném bloku, program přeskočí všechny bloky ošetřující výjimky a bude pokračovat prvním příkazem následujícím za nimi.
Vyskytne-li se v pokusném bloku chyba, funkce ve které se chyba vyskytla, vyvolá v reakci na tuto chybu výjimku. Přitom vytvoří instanci datového typu (libovolného), do které uloží informaci o chybě, která se objevila (pomocí příkazu throw). Program přeruší přirozený běh instrukcí a začne hledat odpovídající ovladač výjimky, který by výjimku ošetřil. Hledání probíhá v blocích, které příkaz throw dynamicky obklopují (začne hledat u aktuálního bloku, nenajde li ovladač zde postupuje do bloku, který obklopuje předchozí blok atd. Pokud není nalezen ovladač v aktuální pozici, přejde do funkce, která ji zavolala a tam opět postupuje v blocích. Pokud není nalezen ovladač ani zde opět přejde do nadřazené funkce atd. Pokud není nalezen odpovídající ovladač ukončí se program s chybou.
Na výjimku je možné pohlížet jako na další datový typ C++, který vrátí volaná metoda. Aby metoda mohla vrátit výjimku, musí při výskytu chyby vytvořit instanci nějakého datového typu, do které vloží informace o chybě, která se objevila. Výjimka se vyvolá pomocí klíčového slova throw.
throw výraz;
Výjimku je poté možné odchytit (zpracovat) pomocí příkazu catch.
main() { … try { f(); } catch (int n) { /* ošetření chyby */ } … } void f() { … if (chyba) throw 5; … }
Aby bylo možné ošetřit blok kódu na výskyt chyby, musí se hlídaný úsek kódu umístit do bloku příkazu try. Blok try sděluje C++, že má provádět příkazy v bloku kódu do té doby než se vygeneruje výjimka. Pokud se výjimka vyskytne, C++ opustí blok try a hledá příslušný blok kódu catch, který výjimku odchytne (zpracuje). Správný blok catch se pozná podle uvedeného typu výjimky uvedeného u příkazu catch (viz příklad). Blok catch se provede do konce a běh programu pokračuje. Pokud výjimka není v bloku try vygenerována, je blok catch při provádění programu přeskočen a pokračuje se dalšími příkazy za blokem catch.
try { // blok příkazů, které potřebujeme kontrolovat na výskyt výjimky } catch (typ_Vyjimky){ /*...*/} { printf("Byla odchycena výjimka typu typVyjimky"); }
příkaz throw odpovídající ovladače throw 5; catch (int n) { … } throw ‘a’; catch (char c) { … } throw “Help!”; catch (const char *s) { … } throw StackUnderfl(); catch (StackUnderfl& s) { … } throw StackOverfl(n); catch (StackOverfl& s) { .. }
Při generování výjimky C++ hledá odpovídající blok catch. C++ pozná správný blok catch podle typu výjimky, který je deklarován v příkazu catch (viz předchozí příklad typ_Vyjimky). Pokud ho nenalezne, předá výjimku o úroveň výše ve volací hierarchii. Dostane-li se výjimka na vrchol hierarchie (hlavní funkce) a není ani zde zpracována, program vypíše chybovou zprávu a ukončí se.
C++ umožňuje efektivně zpracovat více typů výjimek vygenerovaných v jednom bloku try. Pokud potřebujete odchytit více typů výjimek v jednom bloku try stačí uvést za blok try více bloků catch (viz příklad).
try { // blok příkazů a metod pracujících se soubory } catch (int n) // odchytí výjimky typu throw číslo_int { printf("Byla odchycena výjimka typu EOFException"); } catch (char c) // odchytí výjimky typu throw znak { printf("Byla odchycena výjimka typu FileNotFoundException"); } catch (const char *s) // odchytí výjimky typu throw řetězec { printf("Byla odchycena výjimka typu FileNotFoundException"); }
Blok try může obsahovat libovolný počet příkazů, je však výhodnější do bloku try umísťovat příkazy, které spolu souvisí. Usnadňuje to následné ošetření výjimky v bloku catch.