Použití výjimek

Přehled informací

Vymezení pojmu výjimka v C++

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.

Syntaxe (schéma) použití výjimek

  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.

Poznámka - průběhu 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.

Vyvolání výjimky

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.

Syntaxe

  throw výraz;

Výjimku je poté možné odchytit (zpracovat) pomocí příkazu catch.

Příklad použití příkazu throw

  main()
  {
    …   
  try
  { 
    f(); 
  }
  catch (int n) { /* ošetření chyby */ }
    …
  }

  void f()
  { 
      …
    if (chyba) throw 5;
      …
  }

Odchycení (zpracování) výjimky

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.

Příklad použití příkazů try a 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říklad vygenerovaných výjimek a odpovídajících ovladačů

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) { .. }

Poznámka - odchycení výjimek

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.

Poznámka - zpracování více výjimek

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).

Příklad odchycení dvou výjimek

  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");
  }

Poznámka - blok try

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.