10.3. Výjimky

Časová náročnost
Časová náročnost: 25 minut

V jazyce C++ existuje mechanismus, který slouží k obsluze chyb. Nazývá se obsluha výjimek. Obsluha výjimek je založena na třech klíčových slovech:

upozornění
  • Try - zde uvádíme všechny výjimky, které chceme monitorovat
  • Catch - popisuje jak reagovat na vzniklé výjimky
  • Throw - slouží k zahazování (odmítnutí) výjimek

Všechny příkazy programu, které chceme monitorovat se zapíší do bloku try. Příkaz který odmítá výjimku musí být v bloku try umístěn. Výjimka musí být zachycena příkazem catch, který následuje bezprostředně za příkazem try.

Syntaxe je následující:

upozornění
try {
 // blok try
}
catch (typ1 argument) {
 // blok catch
}
catch (typ2 argument) {
 // blok catch
}
 .
 .
 .
catch (typN argument) {
 // blok catch
}


Blok try musí obsahovat tu část programu, kterou chceme monitorovat na výskyt chyb. Když je výjimka odmítnuta,je zachycena odpovídajícím příkazem catch přidruženým k try. Jaký příkaz catch to bude konkrétně určuje typ výjimky - přesněji se porovná typ dat specifikovaný v catch s typem ve výjimce a pokud je nalezena shoda, provede se posloupnost příkazů.

Syntaxe příkazu throw je následující:
throw výjimka;


Příkaz throw musí být spuštěn buď z bloku try, nebo z nějaké funkce, kterou kód v bloku volá. Výjimka je odmítnutá hodnota.

Jestliže odmítneme výjimku, k níž neexistuje odpovídající příkaz catch může dojít k abnormálnímu ukončení programu.

Na prvním příkladu si ukážeme jak jazyk C++ přistupuje k výjimkám.

src/10_3.cpp
Příklad 10.3.
#include <iostream.h>

int main()
{
  cout << "start\n";

  try { // blok try
    cout << "Uvnitr try\n";
    throw 10; // odmitnuti chyby
    cout << "Toto se nevytiskne";
  }
  catch (int i) { // zachyceni chyby
    cout << "Zachycena chyba! Cislo je: ";
    cout << i << "\n";
  }

  cout << "end";

  return 0;
}


Jednoduchý příklad
Příklad:

Jakmile je výjimka odmítnuta, předá se řízení výrazu catch a blok try je ukončen. Po provedení příkazu catch pokračuje řízení programu příkazem následujícím za catch.

Typ výjimky musí souhlasit s typem specifikovaným ve výrazu catch. Pokud tomu tak není, výjimka nebude zachycena a může dojít k chybnému ukončení programu.

Chybný příklad:

#include <iostream.h>

int main()
{
  cout << "start\n";

  try { // blok try
    cout << "Uvnitr try\n";
    throw 10; // odmitnuti chyby
  }
  // nebude fungovat pro vyjimku s datovym typem int
  catch (double i) {
    cout << "Zachycena chyba! Cislo je: ";
    cout << i << "\n";
  }

  cout << "end";

  return 0;
}


Někdy můžeme také chtít, abychom zachytávaly všechny výjimky - ne jen výjimky určitého typu. Použijeme následující formát catch:

upozornění
catch(...) {
  // zpracování všech výjimek
}


Můžeme omezit typy výjimek, které může funkce odmítat zpět do jejich vyvolávače. Může také řídit, jaký typ výjimek, může funkce sama odmítat. Pro aplikaci určitých omezení musíme do definice funkce přidat klauzuli throw.

Syntaxe poté vypadá následovně:

upozornění
návratový-typ jméno-funkce(argumenty) throw(seznam-typů)
{
 // tělo funkce
}


Typy dat oddělené čárkou v poli seznam-typů mohou být funkcí odmítnuty. Pokud nechceme aby funkce zachytávala nějaké výjimky uvedeme prázdný seznam.

Následující příklad ukazuje zachycení všech výjimek - pouze u výjimky typu int bude vypsáno jiné hlášení.

src/10_4.cpp
Příklad 10.4.
#include <iostream.h>

void Xhandler(int test)
{
  try{
    if(test==0) throw test;   // odmita int
    if(test==1) throw 'a';    // odmita char
    if(test==2) throw 123.23; // odmita double
  }
  catch(int i) { // zachytava vyjimky typu int
    cout << "Zachycen int " << i << '\n';
  }
  catch(...) { // zachytava vsechny ostatni vyjimky
    cout << "Zachyceno neco jineho nez int\n";
  }
}

int main()
{
  cout << "start\n";

  Xhandler(0);
  Xhandler(1);
  Xhandler(2);

  cout << "end";

  return 0;
}




Následující příklad ukazuje jak lze omezit typy výjimek, které mohou být funkcí odmítnuty.

src/10_5.cpp
Příklad 10.5.
#include <iostream.h>

// Funkce odmita pouze int, char a double
void Xhandler(int test) throw(int, char, double)
{
  if(test==0) throw test;   // odmita int
  if(test==1) throw 'a';    // odmita char
  if(test==2) throw 123.23; // odmita double
}

int main()
{
  cout << "start\n";

  try{
    Xhandler(0); 
  }
  catch(int i) {
    cout << "Zachyceno int\n";
  }
  catch(char c) { 
    cout << "Zachyceno char\n";
  }
  catch(double d) { 
    cout << "Zachyceno double\n";
  }

  cout << "end";

  return 0;
}