Ošetření chyb a výjimky

Podobné dokumenty
PB161 Programování v jazyce C++ Přednáška 8

PB161 Programování v jazyce C++ Přednáška 9

Jazyk C++ II. Výjimky

PB161 Programování v jazyce C++ Přednáška 9

Výjimky a ošetřování chyb v PHP. Who is General Failure and why is he reading my disk?!

Z. Kotala, P. Toman: Java ( Obsah )

KTE / ZPE Informační technologie

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

Preprocesor. Karel Richta a kol. katedra počítačů FEL ČVUT v Praze. Karel Richta, Martin Hořeňovský, Aleš Hrabalík, 2016

Soubor jako posloupnost bytů

Připravil: David Procházka. Programovací jazyk C++

Tento studijní blok má za cíl pokračovat v základních prvcích jazyka Java. Konkrétně bude věnována pozornost rozhraním a výjimkám.

2) Napište algoritmus pro vložení položky na konec dvousměrného seznamu. 3) Napište algoritmus pro vyhledání položky v binárním stromu.

10. března 2015, Brno Připravil: David Procházka. Programovací jazyk C++

29. Výjimky, jejich vznik, vyhození, odchyt a zpracování. (A7B36PVJ)

Generické programování

Dynamika objektů. Karel Richta a kol. katedra počítačů FEL ČVUT v Praze

PB161 programování v C++ Výjimky Bezpečné programování

17. Projekt Trojúhelníky

Více o konstruktorech a destruktorech

Práce s knihovnami. Karel Richta a kol. katedra počítačů FEL ČVUT v Praze. Karel Richta, Martin Hořeňovský, Aleš Hrabalík, 2016

přetížení operátorů (o)

Dědičnost (inheritance)

Programování v C++ 1, 17. cvičení

8 Třídy, objekty, metody, předávání argumentů metod

PROMĚNNÉ, KONSTANTY A DATOVÉ TYPY TEORIE DATUM VYTVOŘENÍ: KLÍČOVÁ AKTIVITA: 02 PROGRAMOVÁNÍ 2. ROČNÍK (PRG2) HODINOVÁ DOTACE: 1

Zápis programu v jazyce C#

Java - výjimky. private void vstup() throws IOException {... }

IAJCE Přednáška č. 7. řízení semaforu na křižovatce = přepínání červená/oranžová/zelená

IRAE 07/08 Přednáška č. 2. atr1 atr2. atr1 atr2 -33

PB161 Programování v jazyce C++ Přednáška 10

Pokročilé programování v jazyce C pro chemiky (C3220) Pokročilá témata jazyka C++

C++ přetěžování funkcí a operátorů. Jan Hnilica Počítačové modelování 19

Chyby a výjimky. Chyba. Odkud se chyby berou? Kdo chyby opravuje? Co můžete dělat jako programátor? Dvě hlavní metody práce s chybami.

Semin aˇr Java V yjimky Radek Ko ˇc ı Fakulta informaˇcn ıch technologi ı VUT Unor 2008 Radek Koˇc ı Semin aˇr Java V yjimky 1/ 25

Práce se soubory. Základy programování 2 Tomáš Kühr

Ukazatele, dynamická alokace

Výčtový typ strana 67

Syntaxe vyjímek. #include <iostream> #include <string> using namespace std; // Trida vyjimek class Vyjimka { private:

Obsah přednášky 7. Základy programování (IZAPR) Přednáška 7. Parametry metod. Parametry, argumenty. Parametry metod.

Dědění, polymorfismus

Přetěžování operátorů, dynamika objektů 2

IW5 - Programování v.net a C# 4 Pokročilé konstrukce C#

1. Programování proti rozhraní

Struktura programu v době běhu

Algoritmy I. Cvičení č. 2, 3 ALGI 2018/19

Úvod. Karel Richta a kol. katedra počítačů FEL ČVUT v Praze. Karel Richta, Martin Hořeňovský, Aleš Hrabalík,2016

Úvod do programovacích jazyků (Java)

PB161 Programování v jazyce C++ Přednáška 10

Programování v C++ 2, 4. cvičení

Pokročilé programování v jazyce C pro chemiky (C3220) Operátory new a delete, virtuální metody

Úvod do programování - Java. Cvičení č.4

<surface name="pozadi" file="obrazky/pozadi/pozadi.png"/> ****************************************************************************

Pole a Funkce. Úvod do programování 1 Tomáš Kühr

Konstruktory a destruktory

Programování v C++ 3, 3. cvičení

Programování v C++ 1, 5. cvičení

Knihovna XmlLib TXV druhé vydání říjen 2012 změny vyhrazeny

Mělká a hluboká kopie

TŘÍDY POKRAČOVÁNÍ. Události pokračování. Příklad. public delegate void ZmenaSouradnicEventHandler (object sender, EventArgs e);

9. lekce Úvod do jazyka C 4. část Funkce, rekurze Editace, kompilace, spuštění Miroslav Jílek

Jazyk C++, některá rozšíření oproti C

1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:

Úvod do programovacích jazyků (Java)

DUM 06 téma: Tvorba makra pomocí VBA

Pokročilé programování v jazyce C pro chemiky (C3220) Třídy v C++

Zpracoval:

Statické proměnné a metody. Tomáš Pitner, upravil Marek Šabo

7. přednáška - třídy, objekty třídy objekty atributy tříd metody tříd

Množina čísel int stl-set-int.cpp

Teoretické minimum z PJV

Ošetřování chyb v programech

PŘETĚŽOVÁNÍ OPERÁTORŮ

Jazyk C++ I. Šablony 2

Základy C++ I. Jan Hnilica Počítačové modelování 18

Dynamická identifikace typů v C++.

Výjimky. Tomáš Pitner, upravil Marek Šabo

Funkce, intuitivní chápání složitosti

Funkční objekty v C++.

Java Výjimky Java, zimní semestr

Algoritmizace, základy programování, VY_32_INOVACE_PRG_ALGO_01

Programování v C++ 1, 6. cvičení

NPRG031 Programování II 1 / :25:46

NMIN201 Objektově orientované programování 1 / :36:09

Programování v C++ VI

Výjimky. v C# a Javě

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:

Správa paměti. Karel Richta a kol. Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze Karel Richta, 2016

PB161 Programování v jazyce C++ Přednáška 7

Př. další použití pointerů

PB161 Programování v jazyce C++ Přednáška 7

Dědičnost. seskupování tříd do hierarchie. potomek získá všechny vlastnosti a metody. provádí se pomocí dvojtečky za názvem třídy.

8. lekce Úvod do jazyka C 3. část Základní příkazy jazyka C Miroslav Jílek

PB161 Programování v jazyce C++ Přednáška 9

PREPROCESOR POKRAČOVÁNÍ

1. Téma 12 - Textové soubory a výjimky

Datové struktury. alg12 1

Iterační výpočty. Dokumentace k projektu č. 2 do IZP. 24. listopadu 2004

IB111 Programování a algoritmizace. Objektově orientované programování (OOP)

Transkript:

Ošetření chyb a výjimky Karel Richta a kol. katedra počítačů FEL ČVUT v Praze Karel Richta, Martin Hořeňovský, Aleš Hrabalík, 2018 Programování v C++, B6B36PJC 11/2018, Lekce 9a https://cw.fel.cvut.cz/wiki/courses/b6b36pjc/start

Problém Při běhu programu mohou vznikat různé chyby. Například nemusíme mít práva ke čtení/zápisu souboru. Tyto chyby je potřeba nějak ošetřit. Místo, které si umí s chybou poradit, je obvykle jiné, než místo, kde chyba vznikla. Aplikační logika Knihovna Knihovna Low level implementace 2

Problém Při běhu programu mohou vznikat různé chyby. Například nemusíme mít práva ke čtení/zápisu souboru. Tyto chyby je potřeba nějak ošetřit. Místo, které si umí s chybou poradit, je obvykle jiné, než místo, kde chyba vznikla. Aplikační logika Knihovna Knihovna Low level implementace Zde vznikne chyba 3

Problém Při běhu programu mohou vznikat různé chyby. Například nemusíme mít práva ke čtení/zápisu souboru. Tyto chyby je potřeba nějak ošetřit. Místo, které si umí s chybou poradit, je obvykle jiné, než místo, kde chyba vznikla. Zde se chyba ošetří Aplikační logika Knihovna Knihovna Low level implementace Zde vznikne chyba 4

Důsledky K řešení chyb je tedy potřeba přenést informace o chybě z nižších vrstev do vyšších. Existují 3 různé způsoby: Návratové hodnoty Chybové příznaky Výjimky Ve standardní knihovně C++ se vyskytují všechny tři. Části převzaté z C obvykle používají návratové hodnoty. Matematické funkce používají chybové příznaky. STL používá výjimky. 5

Řešení pomocí chybových příznaků Základní schema: int chyba = 0; // globální chybový příznak void f(parametry) { // část kódu, kde může nastat chyba // pokud nastane: // nastaví se chybový příznak na dohodnutou nenulovou hodnotu // - přeruší se normální zpracování a funkce se ukončí // pokud chyba nenastane, nic se neděje, příznak se nenastaví ; f(skutečné parametry); if (chyba) { zpracování chyby // normální zpracování 6

Chybové příznaky Funkce, která narazí na chybu, ji zapíše do globální proměnné. Funkce, která se chce o chybě dozvědět, zkontroluje zapsanou hodnotu. Chybové příznaky se používají v matematické knihovně a v POSIX standardu. Pokud log narazí na chybu, třeba negativní vstup, zapíše do errno hodnotu EDOM. Funkce volající log má následně možnost errno přečíst. Nemění signaturu funkce. double foo = std::log(-1.23); if (errno == EDOM) { std::cout << "log() has failed because: " << std::strerror(errno) << '\n'; >>> log() has failed because: Numerical argument out of domain 7

Chybové příznaky knihovna errno.h Definuje makro errno lze si představit jako deklaraci proměnné int errno = 0; Obsahuje kód poslední zjištěné chyby (0 znamená OK). Nejméně tři konstanty - kódy: EDOM (domain error), ERANGE (range error) a EILSEQ (illegal sequence). Pokud některá funkce narazí na chybu, např. log na negativní vstup, zapíše do errno kód chyby, zde např. hodnotu EDOM. Funkce volající log má následně možnost errno přečíst. enum class errc; http://en.cppreference.com/w/cpp/error/errc 8

Chybové příznaky Problémy Chyby mohou být ignorovány. Programátor musí vynaložit úsilí, aby ignorovány nebyly. Není jisté, kdy a kde k chybě došlo. Pokud po volání funkce nezkontrolujeme errno, už se nedá určit, zda k chybě došlo. Ani není možné zjistit, jestli se chyb nevyskytlo více. Je to spousta kódu, která se špatně čte a špatně píše. Volání funkce následuje mnoho řádků, které čtou errno a reagují na chybu. Funkce se dají skládat, ale pouze za cenu možného přehlédnutí chyby. double sumlogs(const std::vector<double>& numbers) { double result = 0; for (auto n : numbers) { result += std::log(n); return result; 9

Chybové příznaky Problémy Chyby mohou být ignorovány. Programátor musí vynaložit úsilí, aby ignorovány nebyly. double sumlogs(const std::vector<double>& numbers) { double result = 0; for (auto n : numbers) { result += std::log(n); return result; double foo(const std::vector<double>& numbers) { return std::exp(sumlogs(numbers)); Když zavoláme std::log s neplatným parametrem, nastaví se errno. To samé platí o std::exp. Došlo k chybě? Nevíme. 10

Chybové příznaky Problémy Není jisté, kdy a kde k chybě došlo. Pokud po volání funkce nezkontrolujeme errno, už se nedá určit, zda k chybě došlo. Ani není možné zjistit, jestli se chyb nevyskytlo více. // Toto už zkontroluje chybu, ale neví kde nastala double sumlogs(const std::vector<double>& numbers) { double result = 0; for (auto n : numbers) { result += std::log(n); if (errno == EDOM) { // handle error return result; Chybu kontrolujeme, ale nevíme, kdy k ní došlo. V tomto případě to nevadí, ale jindy může. 11

Chybové příznaky Problémy Je to spousta kódu, která se špatně čte a špatně píše. Volání funkce následuje mnoho řádků, které čtou errno a reagují na chybu. Funkce se dají skládat, ale pouze za cenu možného přehlédnutí chyby. double sumlogs(const std::vector<double>& numbers) { double result = 0; for (auto n : numbers) { result += std::log(n); if (errno == EDOM) { std::cerr << "Doslo k chybe v sumlogs: EDOM\n"; return NAN; return result; double foo(const std::vector<double>& numbers) { auto temp = sumlogs(numbers); if (errno == EDOM isnan(temp)) { std::cerr << "foo chyba: suma logaritmu skoncila chybou\n"; return NAN; auto res = std::exp(temp); if (errno == ERANGE) { std::cerr << "foo chyba: vysledek je prilis velky.\n"; return NAN; return res; Zvětšeno na příštím snímku 12

Chybové příznaky Problémy double sumlogs(const std::vector<double>& numbers) { double result = 0; for (auto n : numbers) { result += std::log(n); if (errno == EDOM) { std::cerr << "Doslo k chybe v sumlogs: EDOM\n"; return NAN; return result; double foo(const std::vector<double>& numbers) { auto temp = sumlogs(numbers); if (errno == EDOM isnan(temp)) { std::cerr << "foo chyba: suma logaritmu skoncila chybou\n"; return NAN; auto res = std::exp(temp); if (errno == ERANGE) { std::cerr << "foo chyba: vysledek je prilis velky.\n"; return NAN; return res; 13

Chybové příznaky Problémy double sumlogs(const std::vector<double>& numbers) { double result = 0; for (auto n : numbers) { result += std::log(n); if (errno == EDOM) { std::cerr << "Doslo k chybe v sumlogs: EDOM\n"; return NAN; return result; double foo(const std::vector<double>& numbers) { auto temp = sumlogs(numbers); if (errno == EDOM isnan(temp)) { std::cerr << "foo chyba: suma logaritmu skoncila chybou\n"; return NAN; auto res = std::exp(temp); if (errno == ERANGE) { std::cerr << "foo chyba: vysledek je prilis velky.\n"; return NAN; return res; 14

Řešení pomocí návratových hodnot Základní schema: int f(parametry) { // část kódu, kde může nastat chyba // pokud nastane: // - přeruší se normální zpracování a funkce se ukončí // - návratová hodnota indikuje chybu // pokud chyba nenastane, funkce vrátí hodnotu 0 ; if (f(skutečné parametry)) { zpracování chyby // normální zpracování 15

Řešení pomocí návratových hodnot Funkce, které vrací numerickou hodnotu (tradičně int) Návratová hodnota je pak určuje chybu, ke které došlo při průběhu funkce. Hodnoty značící chybu (nebo úspěch) jsou předem definovány. Funkce často přijímají i tzv. výstupní parametr. Navrácené hodnoty z funkce se pak vrací výš. printf("kolik cisel bude nasledovat?\n"); int n; int res = scanf("%d", &n); if (res!= 1) { printf("to neni cislo\n"); exit(1);... 16

Návratové hodnoty Problémy Chyby mohou být ignorovány. Programátor musí vynaložit úsilí, aby ignorovány nebyly. Pokud někdy ignorujete chybu, její hlášení je navždy ztraceno. Je to spousta kódu, která se špatně čte a špatně píše. Vrácená hodnota z každé funkce se musí uložit, zkontrolovat, vyřešit a případně vrátit z funkce. Funkce se nedají skládat. printf("kolik cisel bude nasledovat?\n"); int n; scanf("%d", &n); for (int i = 0; i < n; ++i) {... 17

Návratové hodnoty Problémy Chyby mohou být ignorovány. Pokud někdy ignorujete chybu, její hlášení je navždy ztraceno. int nacti_cislo() { int temp; scanf("%d", &temp); return temp; printf("kolik cisel bude nasledovat?\n"); int n = nacti_cislo();... Pokud se nepovedlo načíst číslo, v n je podivná hodnota. Zbytek programu o tom neví. 18

Návratové hodnoty Problémy Chyby mohou být ignorovány. Programátor vynaložit úsilí, aby ignorovány nebyly. int nacti_kladne_cislo() { int temp; int res = scanf("%d", &temp); if (res!= 1) { return -1; if (temp < 0) { return -2; return temp; Už nejsme schopni vrátit všechny možné hodnoty datového typu int. Musíme vybrat, které hodnoty obětujeme. 19

Návratové hodnoty Problémy Je to spousta kódu, který se špatně čte i píše. Vrácená hodnota z každé funkce se musí uložit a zkontrolovat; v případě chyby musíme správně zareagovat. Funkce se nedají skládat. int nacti_kladne_cislo() { int temp; int res = scanf("%d", &temp); if (res!= 1) { return -1; if (temp < 0) { return -2; return temp; printf("kolik cisel bude nasledovat?\n"); int cislo = nacti_kladne_cislo(); if (cislo < 0) { if (cislo == -2) { printf("potrebuju KLADNE cislo.\n"); if (cislo == -1) { printf("potrebuju cislo.\n"); exit(1);... Zvětšeno na příštím snímku 20

Návratové hodnoty Problémy int nacti_kladne_cislo() { int temp; int res = scanf("%d", &temp); if (res!= 1) { return -1; if (temp < 0) { return -2; return temp; printf("kolik cisel bude nasledovat?\n"); int cislo = nacti_kladne_cislo(); if (cislo < 0) { if (cislo == -2) { printf("potrebuju KLADNE cislo.\n"); if (cislo == -1) { printf("potrebuju cislo.\n"); exit(1);... 21

Návratové hodnoty Problémy int nacti_kladne_cislo() { int temp; int res = scanf("%d", &temp); if (res!= 1) { return -1; if (temp < 0) { return -2; return temp; printf("kolik cisel bude nasledovat?\n"); int cislo = nacti_kladne_cislo(); if (cislo < 0) { if (cislo == -2) { printf("potrebuju KLADNE cislo.\n"); if (cislo == -1) { printf("potrebuju cislo.\n"); exit(1);... 22

Řešení pomocí výjimek Základní schema: try { // část kódu, kde může nastat chyba // pokud nastane způsobí změnu ve zpracování, tzv. hodí výjimku // - přeruší se normální zpracování, hledá se ovladač této výjimky // - výjimka je identifikována pomocí typu // pokud chyba nenastane, nic se neděje catch ( typ výjimky ) { // zpracování výjimky daného typu catch ( jiný typ výjimky ) { // zpracování výjimky jiného typu // další případné ovladače 23

Výjimky Chyba nemůže být ignorována. Ignorování chyby ukončí proces. Funkce, která hlásí chybu, hodí výjimku. Funkce, která umí chybu zpracovat, ji chytá. Funkce se dají skládat. try { while (true) { new int[100000000ul]; catch (const std::bad_alloc& e) { std::cout << "Allocation failed: " << e.what() << '\n'; 24

Výjimky použití Při hození výjimky dojde k přerušení normálního běhu programu. Příkazy následující po hození výjimky nejsou provedeny. Destruktory objektů na zásobníku ale zavolány jsou. void throws() { std::vector<int> vec; while (true) { std::string str; throw 1; baz(); // Nezavolá se // str je destruováno // vec je destruováno throws(); doesnt(); // Nezavolá se void throws() { std::vector<int> vec; while (true) { std::string str; throw 1; baz(); // Nezavolá se // str je destruováno // vec je destruováno try { throws(); doesnt(); // Nezavolá se catch (int) { std::cout << "Vyjimka chycena.\n"; doesnt(); // Zavolá se 25

Výjimky použití Při hození výjimky dojde k přerušení normálního běhu programu. Příkazy následující po hození výjimky nejsou provedeny. Destruktory objektů na zásobníku ale zavolány jsou. void throws() { std::vector<int> vec; while (true) { std::string str; throw 1; baz(); // Nezavolá se // str je destruováno // vec je destruováno throws(); doesnt(); // Nezavolá se void throws() { std::vector<int> vec; while (true) { std::string str; throw 1; baz(); // Nezavolá se // str je destruováno // vec je destruováno try { throws(); doesnt(); // Nezavolá se catch (int) { std::cout << "Vyjimka chycena.\n"; doesnt(); // Zavolá se 26

Výjimky házení Výjimku hodíme pomocí klíčového slova throw. Hodit se dá libovolný typ/objekt. Obvykle se ale hází nějaký potomek std::exception. Hozená výjimka přeruší normální běh programu a dojde k tzv. stack unwinding. Je to proces, při kterém se postupně ruší objekty na zásobníku a hledá se odpovídající catch blok. Pokud není nalezen vhodný catch blok, dojde k ukončení programu. Nedoporučujeme throw 1; throw "chyba"; std::vector<int> vec; throw &vec; throw std::vector<int>{; Doporučujeme throw std::runtime_error("ooops\n"); throw std::system_error(std::error_code{, "argh\n"); throw std::future_error(std::future_errc::broken_promise); 27

Výjimky chytání Výjimka se chytá pomocí klíčového slova catch(). Chytat se dá libovolný typ. Chytání je polymorfní pokud chytáme třídu, chytáme i její potomky. Kód v catch bloku se provede pouze, pokud je dotyčná výjimka zachycena. Nedoporučujeme catch (...) { // Chytne cokoliv catch (int) { // Chytne throw 1; catch (char) { // Chytne throw 'a'; catch (int*) { // Chytne throw &<int> Doporučujeme catch (const std::exception& ex) { // Chytne exception a potomky catch (const std::bad_alloc& ex) { // Chytne bad_alloc a potomky catch (const std::logic_error& ex) { // Chytne logic_error a potomky 28

Výjimky Pravidla použití VŽDY házejte hodnotou. VŽDY chytejte referencí (pokud můžete, const&) Používejte své výjimky, které dědí z nějaké standardní výjimky. Nepoužívejte catch(...). 29

Výjimky házení, chytání a polymorfismus Jak jsme si řekli, chytání výjimek je polymorfní. Házení ale není. Co to znamená? class B {; class D : public B {; void f(b& throwable) { throw throwable; D status; try { f(status); catch (D& e) { std::cout << "Chytil jsem D!\n"; catch (...) { std::cout << "To je divny...\n"; >>> To je divny... class B { public: virtual void raise() {throw *this; ; class D : public B { public: virtual void raise() {throw *this; ; void f(b& throwable) { throwable.raise(); D status; try { f(status); catch (D& e) { std::cout << "Chytil jsem D!\n"; catch (...) { std::cout << "To je divny...\n"; >>> Chytil jsem D! 30

Výjimky Problémy Cesta kódem není jasná U žádného řádku si nemůžeme být jisti, kam bude pokračovat exekuce. Zpočátku jsou neintuitivní. Popravdě, často i později. Dlouho byly používány špatně. Stále často jsou. int* nacti_cisla(int n) { int* pole = new int[n]; for (int i = 0; i < n; ++i) { pole[i] = nacti_cislo(); // Tahle funkce rozhodně nehází výjimky. Doufám. return pole; 31

Děkuji za pozornost. 32