C++ výjimky
V tomto článku je vysvětleno zpracování výjimek v jazyce C++. Je tedy popsáno, co to vlastně výjimka je a jak ji lze zachytit.
Dále je v článku popsáno, co se stane, když se výjimka nezachytí a nechybí ani krátká zmínka o úniku paměti.
28.2.2011 12:00 |
Petr Sklenička
| Články autora
| přečteno 17251×
Jak již samotný název napovídá, výjimka bude něco, co se nestává příliš často, ale stát se to může. V programování se výjimkou
rozumí nějaká neočekávaná událost, která může vést i ke zhroucení samotného programu. Pravděpodobně nejčastějším příkladem, na
jakém se začínají vysvětlovat výjimky, je dělení nulou. Dejme tomu, že v našem programu očekáváme od uživatele zadání dvou čísel,
které následně chceme mezi sebou vydělit. Když bude vše dle našeho očekávání, uživatel zadá například čísla 6 a 3, program
vypočte podíl, vrátí číslo 2 a vše je jak má být. Problém nastane, pokud jako druhé číslo zadá nulu. To je pro nás výjimečná
situace, neboť nulou dělit nelze. Proto je třeba tuto možnost ohlídat, aby nedošlo ke zhroucení programu. K tomuto účelu slouží
právě výjimky.
Princip výjimek spočivá v tom, že část kódu, ve kterém může nastat výjimka, uzavřeme do bloku try . V případě,
že v bloku try dojde k nějaké nečekáné situaci, řízení programu se předá do bloku catch a provedou se
příkazy, umístěné v tomto bloku. Pokud k žádné výjimce nedojde, program bude pokračovat normálně dál s tím, že blok catch
se přeskočí. Základní syntaxe v C++ tedy vypadá takto:
try
{
// Nejaky kod, ktery muze zpusobit vyjimku
}
catch (Typ vyjimky)
{
// Kod, ktery se provede pri vyvolani vyjimky
}
V předchozím odstavci jsme řešili problém dělení nulou. Nyní si ukážeme již přímo konkrétní kód, který bude dělit dvě čísla, přičemž
děleni nulou bude ošetřeno.
int main()
{
double a, b;
cin >> a;
cin >> b;
try
{
if (b == 0)
throw "Deleni nulou.\n";
cout << a / b << endl;
}
catch (const char* exception)
{
cout << "Byla zachycena vyjimka - " << exception;
}
return 0;
}
V kódu se objevuje klíčové slovo throw . To slouží k vyvolání výjimky, čili pokud je b rovno nule,
pomocí throw se vyhodí výjimka "Deleni nulou" a program přejde na blok catch , který očekává konstantní
znakový ukazatel. Podotýkám, že použití mechanismu výjimek není v tomto případě nijak zvlášť nutné, neboť přímo tento případ
by bylo jednodušší ošetřit prostou podmínkou, ale příklad slouží jako ukázka. Samozřejmostí je, že při psaní programů mohou nastat
i jiné výjimky, než jen obyčejné dělení nulou. Může jich být opravdu mnoho, záleží především na povaze programu - problém může
nastat v případě, že se nelze připojit k FTP serveru, že není možné číst ze souboru, nelze alokovat paměť apod. Snahou programátora
by mělo být to, aby výjimky, které v jeho programu mohou nastat, co nejlépe ošetřil.
Vzhledem k tomu, že v programu většinou může dojít k více výjimkám, je možné napsat více bloků catch , přičemž
každý bude mít na starost konkrétní typ výjimky. Jeden bude například hlídat zápis za konec pole, druhý připojení k internetu,
třetí bude mít na starost chování jaderného reaktoru atd... Existuje však blok catch , který dokáže zachytit všechny
výjimky.
try
{
NejakaNebezpecnaFunkce();
}
catch (...)
{
// Timto blokem je mozne chytit kazdou vyjimku
}
Čistě tento způsob však není přilíš vhodný, neboť je lepší každou výjimku ošetřit rozdílným způsobem, což v tomto případě nejde.
Lepší tedy je napsat více bloků catch , a blok catch (...) dát až jako poslední, jako takový "záložní".
Výjimky mohou být také součástí tříd. Můžeme tedy vytvořit jiný typ objektu pro různé výjimky, které budeme chtít zachytit,
přičemž samotný objekt může nést informace, týkající se vzniklého problému. Jestliže se výjimka, kterou chceme odchytit, vztahuje
na něco, co se děje v nějaké třídě, bývá vhodné definovat typ výjimky jako vnořenou třídu. Pro jednoduchost můžeme uvažovat, že
máme třídu MyStructure , v níž máme veřejně deklarovanou třídu WrongIndex . Třída MyStructure
bude nějakým způsobem pracovat s polem (je vcelku nepodstatné, jakým způsobem). Jestliže zadáme špatnou hodnotu indexu, můžeme
vyvolat výjimku, která bude typu WrongIndex . Blok catch (který se mimochodem často označuje jako
handler) by vypadal následovně:
catch (MyStructure::WrongIndex&)
{
// neco...
}
Třída MyStructure , společně s vnořenou třídou WrongIndex je k dispozici
zde. Za zmínku ještě stojí, že
ve výjimkách lze vytvořit jakousi "hierarchii" pomocí dědičnosti. Není tedy žádný problém vytvořit třídu výjimky, která bude
dědit například z třídy WrongIndex . Stejně tak vytvoříme-li třídu, která bude dědit ze třídy MyStructure ,
tak tato nová třída zdědí i třídu WrongIndex .
Co se stane, když se výjimka nezachytí
Jak jsem již výše psal, nastane-li v programu něco neočekávaného, často tato situace vede k ukončení programu. Podívejme se
na to ale trochu podrobněji. Nezachycená výjimka totiž nezpůsobí okamžité ukončení programu. Místo toho nejprve v programu dojde k
zavolání funkce terminate() , přičemž tato funkce volá funkci abort() . Toto standardní chování je však
možné v programu upravit, a to díky funkci set_terminate() . Deklaraci obou těchto funkcí (terminate() a
set_terminate() je možné najit v hlavičkovém souboru exception . Budeme-li tedy chtít změnit chování
programu při nezachycené výjimce, můžeme to provést takto:
#include <exception>
#include <iostream>
using namespace std;
void myFunction()
{
cerr << "Nezachycena vyjimka.\n";
cerr << "Program bude ukoncen.\n";
exit(1);
}
int main()
{
set_terminate(myFunction);
int a, b, c;
cin >> a >> b;
if (b == 0) throw "Nezachycena vyjimka";
c = a / b;
cout << c;
return 0;
}
V tomto případě, pokud bude hodnota b rovna nule, dojde k vyvolání výjimky. V programu ale není žádný odpovídající
blok catch , který by výjimku ošetřil. Proto se zavolá funkce terminate() , která zavolá naší funkci
myFunction . Co dělá tato funkce už není třeba komentovat.
Únik paměti
Nyní již víme, k čemu výjimky slouží a jak se používají. Nicméně tak jako všechno ostatní, tak i výjimky mají své nevýhody.
S jejich použitím se zvětšuje velikost výsledného programu a program se stává o něco pomalejším. Výjimky si také příliš dobře
nerozumí se šablonami, neboť šablony funkcí mohou vyvolávat různé výjimky v závislosti na konkrétní specializaci. Někdy také
může nastat problém s dynamickou alokací paměti. V následující ukázce pochopíte, o čem mluvím.
try
{
p = new int [100];
if (myFunction() == false)
throw "Nejaka vyjimka";
/*
Nejaky dalsi kod
*/
delete [] p;
}
Zde může nastat problém. V případě, že funkce myFunction vrátí logickou hodnotu false , vyvolá se výjimka
a řízení programu se předá odpovídajícímu bloku catch . Mimo to dojde k tomu, že ztratíme ukazatel p a
blok paměti, na níž ukazatel ukazoval, zůstane nepřístupný. Tomuto problému se říká únik paměti. Jak tomuto úniku předejít? Poměrně
jednoduše.
int *p = new int [100];
try
{
if (myFunction() == false)
throw "Nejaka vyjimka";
delete [] p;
cout << "Pamet uvolnena.\n";
}
catch (const char *ex)
{
delete [] p;
cerr << "Vyjimka zachycena.\nPamet uvolnena.\n";
}
Toto řešení má však tu nevýhodu, že zvyšuje možnost přehlédnutí dalších chyb. Závěrem se tedy dá říct to, že ošetření výjimek
může být v některých programech velmi důležité, které ale na druhou stranu může vyžadovat velké úsilí. Proto je vždy vhodné
používat výjimky s mírou a rozumem.
Verze pro tisk
|
Příspívat do diskuze mohou pouze registrovaní uživatelé.
|
|

Vyhledávání software

Vyhledávání článků
28.11.2018 23:56 /František Kučera Prosincový sraz spolku OpenAlt se koná ve středu 5.12.2018 od 16:00 na adrese Zikova 1903/4, Praha 6. Tentokrát navštívíme organizaci CESNET. Na programu jsou dvě přednášky: Distribuované úložiště Ceph (Michal Strnad) a Plně šifrovaný disk na moderním systému (Ondřej Caletka). Následně se přesuneme do některé z nedalekých restaurací, kde budeme pokračovat v diskusi.
Komentářů: 1
12.11.2018 21:28 /Redakce Linuxsoft.cz 22. listopadu 2018 se koná v Praze na Karlově náměstí již pátý ročník konference s tématem Datová centra pro business, která nabídne odpovědi na aktuální a často řešené otázky: Jaké jsou aktuální trendy v oblasti datových center a jak je optimálně využít pro vlastní prospěch? Jak si zajistit odpovídající služby datových center? Podle jakých kritérií vybírat dodavatele služeb? Jak volit vhodné součásti infrastruktury při budování či rozšiřování vlastního datového centra? Jak efektivně datové centrum spravovat? Jak co nejlépe eliminovat možná rizika? apod. Příznivci LinuxSoftu mohou při registraci uplatnit kód LIN350, který jim přinese zvýhodněné vstupné s 50% slevou.
Přidat komentář
6.11.2018 2:04 /František Kučera Říjnový pražský sraz spolku OpenAlt se koná v listopadu – již tento čtvrtek – 8. 11. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma umění a technologie, IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář
4.10.2018 21:30 /Ondřej Čečák LinuxDays 2018 již tento víkend, registrace je otevřená.
Přidat komentář
18.9.2018 23:30 /František Kučera Zářijový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 20. 9. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář
9.9.2018 14:15 /Redakce Linuxsoft.cz 20.9.2018 proběhne v pražském Kongresovém centru Vavruška konference Mobilní řešení pro business.
Návštěvníci si vyslechnou mimo jiné přednášky na témata: Nejdůležitější aktuální trendy v oblasti mobilních technologií, správa a zabezpečení mobilních zařízení ve firmách, jak mobilně přistupovat k informačnímu systému firmy, kdy se vyplatí používat odolná mobilní zařízení nebo jak zabezpečit mobilní komunikaci.
Přidat komentář
12.8.2018 16:58 /František Kučera Srpnový pražský sraz spolku OpenAlt se koná ve čtvrtek – 16. 8. 2018 od 19:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát jsou tématem srazu databáze prezentaci svého projektu si pro nás připravil Standa Dzik. Dále bude prostor, abychom probrali nápady na využití IoT a sítě The Things Network, případně další témata.
Přidat komentář
16.7.2018 1:05 /František Kučera Červencový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 19. 7. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát bude přednáška na téma: automatizační nástroj Ansible, kterou si připravil Martin Vicián.
Přidat komentář
Více ...
Přidat zprávičku
 Poslední diskuze
31.7.2023 14:13 /
Linda Graham iPhone Services
30.11.2022 9:32 /
Kyle McDermott Hosting download unavailable
13.12.2018 10:57 /
Jan Mareš Re: zavináč
2.12.2018 23:56 /
František Kučera Sraz
5.10.2018 17:12 /
Jakub Kuljovsky Re: Jaký kurz a software by jste doporučili pro začínajcího kodéra?
Více ...
|