10. března 2015, Brno Připravil: David Procházka Práce s výjimkami Programovací jazyk C++
K čemu slouží výjimky Strana 2 / 25 Obsah přednášky 1 K čemu slouží výjimky 2 Vytváření výjimek 3 Speciální případy 4 Hierarchie výjimek 5 Standardní výjimky 6 Shrnutí
K čemu slouží výjimky Strana 3 / 25 Jak se může program zachovat při chybě Dříve byl obvyklý způsob zavolat metodu abort. Metoda okamžitě vyprázdnila vyrovnávací pamět, ukončila celý program, vrátila číslo nadřazeného procesu, vypsala na chybový výstup hlášku o ukončení. Alternativně se využívala metoda exit. Nejednalo se o elegantní řešení, proto byl preferován mechanismus návratových hodnot. Metoda v tomto případě neukončuje program, jen signalizuje chybu. Návratovou hodnotu je však možné ignorovat. Návratová hodnota nenese obvykle komplexnější informace o chybě.
K čemu slouží výjimky Strana 4 / 25 Výjimky Vyjímka představuje zajímavý způsob, jak signalizovat programu, že v určité entitě nastala chyba. Řeší problémy zmíněné u návratových hodnot. Výjimky používá řada funkcí/metod (přístup pomocí metody at() na místo v řetězci). Je vyvolána pomocí příkazu throw. Hodnotou, která je jako vyjímka vyhozena může být jednoduchý datový typ, obvykle používáme objekty. Výjimky si můžeme nadefinovat sami, použít standardní výjimky a výjimky od nich odvozené (doporučeno). Výjimka je odchytávána v bloku kódu označeném jako try. Řešena je v bloku catch(). Užití výjimek výrazně zpomaluje program.
K čemu slouží výjimky Strana 5 / 25 Implementace 1 try { 2 // pokus o operaci potencialne vyhazujici vyj. 3 } catch ( myexception &e) { 4 // osetreni neplatneho pokusu 5 } V bloku catch je uveden odkaz na výjimku. Ve skutečnosti se však jedná o odkaz na kopii. Původní výjimka obvykle v době zpracování již neexistuje.
K čemu slouží výjimky Strana 6 / 25 Příklad ošetření výjimky u metody at() Dojde-li v bloku try k vyvolání výjimky, běh programu se přeruší a přejde se k nejbližšímu handleru výjimek catch. 1 # include < exception > 2 # include < string > 3 4 int main () { 5 std :: string s(" 1234 "); 6 try { 7 s.at (5); 8 std :: cout << " toto se nikdy nevypise "; 9 } catch ( exception &e) { 10 std :: cerr << " Nastala chyba " << std :: endl ; 11 std :: cerr << e. what () << std :: endl ; 12 } 13...
Vytváření výjimek Strana 7 / 25 Obsah přednášky 1 K čemu slouží výjimky 2 Vytváření výjimek 3 Speciální případy 4 Hierarchie výjimek 5 Standardní výjimky 6 Shrnutí
Vytváření výjimek Strana 8 / 25 Příklad Zlomek Vytvořte třídu reprezentující zlomek, který obsahuje atributy citatel a jmenovatel. Dále má metodu vyděl, která vyhazuje výjimku v případě dělení nulou. Výjimku reprezentujte vlastní třídou obsahující popis problému (lze rozšířit o další informace hodnoty čitatele a jmenovatele, atp.). 1 class MatChyba { 2 private : 3 std :: string m_popis ; 4 public : 5 void MatChyba ( std :: string d) { m_ popis = d; } 6 std :: string getpopis () { return m_ popis ; } 7 };
Vytváření výjimek Strana 9 / 25 Ruční vyhození výjimek Pokud má mít některá funkce možnost vyvolat výjimku, musí to být uvedeno v deklaraci funkce (metody). Pokud může funkce vracet výce typů výjimek, musí být v závorce všechny. 1 class Zlomek { 2 private : 3 int m_ citatel, m_ jmenovatel ; 4 public : 5 Zlomek ( int citatel, jmenovatel ){ 6 m_ citatel = citatel ; 7 m_ jmenovatel = jmenovatel ; 8 } 9 double vydel () throw ( MatChyba ); 10 };
Vytváření výjimek Strana 10 / 25 Implementace metody vydel() 1 double Zlomek :: vydel () throw ( MatChyba ){ 2 if ( m_ jmenovatel == 0) { 3 MatChyba v(" Deleni nulou ve zlomku "); 4 throw v; 5 // lze vyhodit i nepojmenovanou instanci tridy 6 // throw MatChyba (" Popis problemu "); 7 } 8 return (( double ) m_citatel / m_jmenovatel ); 9 } Je důrazně doporučováno vyhazovat výjimky hodnotou a odchytávat odkazem.
Vytváření výjimek Strana 11 / 25 Jak výjimku zpracujeme? 1 Zlomek * z = new Zlomek (10,0); 2 3 try { 4 std :: cout << " 10/0= " << z-> vydel () << std :: endl ; 5 std :: cout << " Pokud je delitel!= 0 vypise se to"; 6 } catch ( MatChyba & v) { // pokud je vyhozena Vyjimka 7 std :: cout << v. vrat () << std :: endl ; 8 } catch ( LogChyba &j) { // pokud jina 9... 10 // opetovne uvolneni vyjimky pro zpracovani 11 // specialni pripad, bezne nedelame! 12 throw ; 13 }
Vytváření výjimek Strana 12 / 25 Odchycení všech výjimek V závorce jsou opravdu tři tečky. 1 try { 2 // vyvolani vyjimky 3 } catch (...) { 4 // osetreni 5 } Nelze však identifikovat typ výjimky druh problému.
Speciální případy Strana 13 / 25 Obsah přednášky 1 K čemu slouží výjimky 2 Vytváření výjimek 3 Speciální případy 4 Hierarchie výjimek 5 Standardní výjimky 6 Shrnutí
Speciální případy Strana 14 / 25 Ošetření zrušení objektu speciální případ! 1 // nekde v metode 2 Trida * instance = new Trida ; 3 4... 5 // kod, ktery potencialne vyhodi vyjimku 6 // tato vyjimka je vyslana mimo metodu 7... 8 9 delete instance ; 10... Pokud bude vyhozena výjimka, objekt se nikdy nezruší.
Speciální případy Strana 15 / 25 Ošetření zrušení objektu řešení 1 Trida * instance = new Trida ; 2 3 try { 4 // kod, ktery potencialne vyhazuje vyjimku 5 } catch ( exception &e) { 6 7 delete instance ; 8 //" pozastavenou " vyjimku je treba zase uvolnit 9 throw ; 10 } a) Nelze to ošetřit podmínkou? b) Metoda nesmí výjimku odchytit a zrušit bez toho, že by problém vyřešila. Pokud problém který vyhození způsobil setrvává, musí být výjimka (znovu) vypuštěna.
Hierarchie výjimek Strana 16 / 25 Obsah přednášky 1 K čemu slouží výjimky 2 Vytváření výjimek 3 Speciální případy 4 Hierarchie výjimek 5 Standardní výjimky 6 Shrnutí
Hierarchie výjimek Strana 17 / 25 Vytváření výjimek a dědičnost 1 class MatChyba { 2 private : 3 std :: string m_popis ; 4 public : 5 MatChyba ( std :: string popis ){ m_ popis = popis ;} 6 std :: string getpopis () { return m_ popis ; } 7 }; 8 9 class DeleniNulou : public MatChyba { 10 private : 11 int m_ delenec ; 12 public : 13 DeleniNulou ( std :: string t, int d): Vyjimka (t){ 14 m_delenec =d; 15 } 16 int getdelenec () { return m_ cislo ; } 17 };
Hierarchie výjimek Strana 18 / 25 Řešení jejich odchycení již bylo zmíněno 1 try { 2 // vyvolani v. 3 } catch ( DeleniNulou & v) { 4 // osetreni 5 } catch ( MatChyba & v) { 6 // osetreni 7 } Je nutné dávat si pozor na pořadí v jakém výjimky odchytáváme (potomek může vystupovat v roli předka!). Pokud nejdříve odchytáváte předka, odchytí se i potomek!
Standardní výjimky Strana 19 / 25 Obsah přednášky 1 K čemu slouží výjimky 2 Vytváření výjimek 3 Speciální případy 4 Hierarchie výjimek 5 Standardní výjimky 6 Shrnutí
Standardní výjimky Strana 20 / 25 Standardní výjimky Spíše, než definovat si vlastní výjimky, je vhodné využívat standardních výjimek, případně odvozené. Výjimky jsou odvozeny od třídy exception. Tato třída obsahuje virtuální metodu what(). Z ní jsou odvozené logic error (chyby v logice programu) a runtime error (chyby zjistitelné až za běhu programu). Abychom mohli používat standardní výjimky, je nutné načíst stdexcept. Pokud uživateli nevyhovuje žádná ze standardních výjimek, je vhodné odvodit vlastní z této hierarchie. Proto je vhodné, aby se programátor nejdříve dobře seznámil se standardními výjimkami.
Standardní výjimky Strana 21 / 25 Standardní výjimky Z logic error se odvozují: domain error asinu je předávána hodnota mimo interval -1, 1, invalid argument funkci byla předána neočekávaná hodnota, length error pro požadovanou operaci není dostatek místa (append), out of bounds obvykle špatný index. Z runtime error se odvozují: underflow error pokud při výpočtech v plovoucí čárce vyjde číslo, které je menší, než minimální zobrazitelné, overflow error výsledek číslo je větší, než maximální zobrazitelné, range error výsledek je mimo obor hodnot. A znich zase další...
Standardní výjimky Strana 22 / 25 Příklad standardní výjimky 1 Trida * objekt ; 2 try { 3 objekt = new Trida ; 4 } catch ( std :: bad_alloc &b) { 5 std :: cout << " Vyhodil vyjimku " << std :: endl ; 6 } Vyvolání výjimky lze zamezit a provést ruční ošetření. Je ale nutné pečlivě hlídat potenciální chyby. Nicméně v některých situacích, kdy je potřeba optimalizovat na výkon se to může hodit (nothrow).
Standardní výjimky Strana 23 / 25 Příklad na odvození výjimky Zlomek Zkuste se zamyslet nad příkladem se zlomkem a upravit jej tak, aby podporoval některou z hierarchie standardních výjimek. Dále se pokuste vytvořit vlastní a zařadit ji do hierarchie.
Shrnutí Strana 24 / 25 Obsah přednášky 1 K čemu slouží výjimky 2 Vytváření výjimek 3 Speciální případy 4 Hierarchie výjimek 5 Standardní výjimky 6 Shrnutí
Shrnutí Strana 25 / 25 Shrnutí Výjimky jsou doplněk Výjimky nenahrazují zcela používání návratových hodnot funkcí/metod jako indikátoru chybového stavu. Jedná se o určitý komplexní doplněk, který umožňuje lépe předávat informace o tom co se vlastně stalo a lépe také řešit situace, kde může dojít řadě různých chyb (najednou). Předcházejte výjimkám Je obvykle vhodné předcházet vyhození výjimky kontrolou vstupních hodnot atp. Výjimka má roli určité záhranné brzdy.