Prezentace se nahrává, počkejte prosím

Prezentace se nahrává, počkejte prosím

PB161 PB161 – Programování v jazyce C++ Objektově Orientované Programování STL algoritmy, Funktory, Výjimky STL algs, Výjimky, Functor 3.11.2014 1.

Podobné prezentace


Prezentace na téma: "PB161 PB161 – Programování v jazyce C++ Objektově Orientované Programování STL algoritmy, Funktory, Výjimky STL algs, Výjimky, Functor 3.11.2014 1."— Transkript prezentace:

1 PB161 PB161 – Programování v jazyce C++ Objektově Orientované Programování STL algoritmy, Funktory, Výjimky STL algs, Výjimky, Functor 3.11.2014 1

2 PB161 Organizační - zvané přednášky 24.11. Juraj Michálek (YSoft) 1.12. Jiří Weiser (Laboratoř Paradise) - C++11 STL algs, Výjimky, Functor 3.11.2014 2

3 PB161 STL Algoritmy STL algs, Výjimky, Functor 3.11.2014 3

4 PB161 STL zavádí nové koncepty 1.Kontejnery ●objekty, které uchovávají jiné objekty bez ohledu na typ ●kontejnery různě optimalizovány pro různé typy úloh ●např. std::string (uchovává pole znaků) ●např. std::list (zřetězený seznam) 2.Iterátory ●způsob (omezeného) přístupu k prvkům kontejneru ●např. std::string.begin() ●přetížené operátory ++ pro přesun na další prvek atd. 3.Algoritmy ●běžné operace vykonané nad celými kontejnery ●např. sort(str.begin(), str.end()) STL algs, Výjimky, Functor 3.11.2014 4 6. Přednáška

5 PB161 STL Algoritmy Standardní metody pracující nad kontejnery Obsahuje často používané operace (hledání, řazení…) Mohou kontejner číst nebo i měnit Často využívají (jako argument) iterátory STL algs, Výjimky, Functor 3.11.2014 5 // sort algorithm example from http://www.cplusplus.com/reference/algorithm/sort/ #include using namespace std; int main () { vector myvector; // fill vector by values sort (myvector.begin(), myvector.end()); return 0; }

6 PB161 Algoritmy - dokumentace STL algs, Výjimky, Functor 3.11.2014 Funkce dostupné v http://www.cplusplus.com/reference/algorithm/ Ukázka syntaxe na for_each 6

7 PB161 Základní dostupné STL algoritmy Vyhledávání, statistika (nemodifikují cílový kontejner) find(), search(), count()… Modifikují cílový kontejner copy(), remove(), replace(), transform() Aplikace uživatelské funkce for_each() – (typicky) nemodifikuje původní kontejner transform() – (typicky) modifikuje obsah kontejneru Řadící sort() vhodný řadící algoritmus automaticky vybrán dle typu kontejneru Spojování rozsahů, Minimum, maximum… A spousta dalších http://www.cplusplus.com/reference/algorithm/ STL algs, Výjimky, Functor 3.11.2014 7

8 PB161 STL algs, Výjimky, Functor 3.11.2014 8 Převzato z http://www.cplusplus.com/reference/algorithm

9 PB161 STL algs, Výjimky, Functor 3.11.2014 9 Převzato z http://www.cplusplus.com/reference/algorithm

10 PB161 STL algoritmy – find STL algs, Výjimky, Functor 3.11.2014 10 #include using std::cout; using std::endl; int main() { std::list myList; myList.push_back(1);myList.push_back(2);myList.push_back(3); myList.push_back(4);myList.push_back(5); // 1, 2, 3, 4, 5 std::list ::iterator iter; // Find item with value 4 if ((iter = std::find(myList.begin(), myList.end(), 4)) != myList.end()) { cout << *iter << endl; } // Try to find item with value 10 if ((iter = std::find(myList.begin(), myList.end(), 10)) != myList.end()) { cout << *iter << endl; } else cout << "10 not found" << endl; return 0; }

11 PB161 STL algoritmy – for_each a transform STL algs, Výjimky, Functor 3.11.2014 11 #include using std::cout; using std::endl; int increase10(int value) { return value + 10; } void print(int value) { cout << value << endl; } int main() { std::list myList; // … fill something into myList // Apply function to range (typically non-modifying) std::for_each(myList.begin(), myList.end(), print); // Apply function to range (will work only for integers) (modifying) std::transform(myList.begin(),myList.end(),myList.begin(),increase10); return 0; } for_each může také modifikovat kontejner Pokud je hodnota předávána referencí print(int& value) Pro modifikaci používejte ale raději transform

12 PB161 STL algoritmy – callback funkce Některé algoritmy berou jako parametr funkci ●aplikují ji na prvky kontejneru Může být klasická C funkce (např. print() ) Může být static metoda objektu (viz. dále) Může být objekt s přetíženým operátorem() ●tzv. functor, viz dnes později Může být lambda (C++11, pozdější přednáška) STL algs, Výjimky, Functor 3.11.2014 12 std::for_each(myList.begin(), myList.end(), print); template Function for_each(InputIterator first, InputIterator last, Function f) { for ( ; first!=last; ++first ) f(*first); return f; }

13 PB161 STL algoritmy – sort STL algs, Výjimky, Functor 3.11.2014 13 // sort algorithm example from http://www.cplusplus.com/reference/algorithm/sort/ #include using namespace std; bool myfunction (int i,int j) { return (i { "@context": "http://schema.org", "@type": "ImageObject", "contentUrl": "http://images.slideplayer.cz/11/2932111/slides/slide_13.jpg", "name": "PB161 STL algoritmy – sort STL algs, Výjimky, Functor 3.11.2014 13 // sort algorithm example from http://www.cplusplus.com/reference/algorithm/sort/ #include using namespace std; bool myfunction (int i,int j) { return (i

14 PB161 Funkční objekty STL algs, Výjimky, Functor 3.11.2014 14

15 PB161 Funkční objekt - motivace Z C/C++ jsou známé tzv. callback funkce ●pomocí funkčního ukazatele je možné předat jako parametr ukazatel na funkci, která je později zavolána ●používá se například u STL algoritmů ● std::for_each(l.begin(),l.end(), print); Co když chceme přičítat pomoc std::transform číslo 10? ●vytvoříme funkci int add10(int value){return value+10;} ● std::transform(l.begin(),l.end(),l.begin(),add10); Co když chceme přičítat libovolné číslo? STL algs, Výjimky, Functor 3.11.2014 15

16 PB161 Funkční objekt – Functor Objekt, který může zavolán, jako by to byla běžná funkce ●dosáhneme pomocí přetíženého operátoru () ● A prom; prom(5); Operátor () musíme přetížit pro všechny potřebné typy a počty argumentů ●tj. pro každou funkci, kterou chceme functorem nahradit ●jeden functor může nahrazovat několik funkcí (jak?) Pokud se pokusíme použít objekt jako functor a neexistuje odpovídající přetížený operátor () ●error: no match for call to '(typ_objektu) (typ_argumentů)' ●stl_algo.h:4688:2: error: no match for call to '(A) (int&)' STL algs, Výjimky, Functor 3.11.2014 16

17 PB161 Functor - ukázka STL algs, Výjimky, Functor 3.11.2014 17 #include class CAddX { int m_whatAdd; public: CAddX(int whatAdd) : m_whatAdd(whatAdd) {} void set(int whatAdd) { m_whatAdd = whatAdd; } int operator () (int value) { return value + m_whatAdd; } }; int main() { std::list myList; myList.push_back(1); myList.push_back(2); myList.push_back(3); myList.push_back(4); CAddX variableAdder(3); // variableAdder is functor object, now adding number 3 transform(myList.begin(), myList.end(), myList.begin(), variableAdder); // change added value variableAdder.set(101); transform(myList.begin(), myList.end(), myList.begin(), variableAdder); return 0; } Nyní přičítač trojky Nyní přičítač stojedničky

18 PB161 Functory – vhodnost použití Výhodou je možnost uchovávat (a měnit) stav functoru ●u funkcí bychom museli použít globální proměnné Functor může být výrazně rychlejší než funkce ●překladač může vložit kód functoru namísto volání ●u funkčních ukazatelů (callback) není možné Využívá myšlenek z funkcionálním programování ●současné imperativní jazyky mají podporu pro některé funkční prvky ●Functor, delegates a lambda výrazy... (C++11, C#...) STL algs, Výjimky, Functor 3.11.2014 18

19 PB161 Příklad - kompozice funktorů Aplikace série funkcí na zadaný argument Např. pseudozápis 'a(b(c(d(5))))' znamená, že funkce a, b, c a d jsou aplikovány na argument 5. Úkolem je vytvořit program umožňující vytvářet (aritmetické) funkce složené z jednodušších funktorů Definice vhodného rozhraní a využití dědičnosti STL algs, Výjimky, Functor 3.11.2014 19

20 PB161 Hierarchie STL algs, Výjimky, Functor 3.11.2014 20 UnaryFunction i FunctionCompositor mají přetížený operátor () a budou použity jako functory

21 PB161 STL algs, Výjimky, Functor 3.11.2014 21 class UnaryFunction { public: virtual ~UnaryFunction() {} virtual int operator() (int arg) const = 0; }; class UnaryNumericFunction : public UnaryFunction { public: UnaryNumericFunction(int rightOperand) : rightOperand_m(rightOperand) {} virtual int rightOperand() const { return rightOperand_m; } virtual void setRightOperand(int r) { rightOperand_m = r; } private: int rightOperand_m; }; class Adder : public UnaryNumericFunction { public: Adder(int r) : UnaryNumericFunction(r) {} int operator() (int arg) const { return arg + rightOperand(); } }; class Multiplier : public UnaryNumericFunction { public: Multiplier(int r) : UnaryNumericFunction(r) {} int operator() (int arg) const { return arg * rightOperand(); } }; Přetížíme operátor () pro aplikaci unární funkce Numerická unární funkce je functor s parametrizací v rightOperand_m V přetiženém operátoru () přičítáme Parametrizace functoru

22 PB161 STL algs, Výjimky, Functor 3.11.2014 22 // Function for deallocation void delete_ptr(UnaryFunction* ptr) { delete ptr; } class FunctionCompositor { public: FunctionCompositor() {} ~FunctionCompositor() { // Use for_each algorithm to deallocate separate functions std::for_each(functions_m.begin(), functions_m.end(), delete_ptr); } void appendFunction(UnaryFunction* fn) { functions_m.push_back(fn); } void prependFunction(UnaryFunction* fn) { functions_m.push_front(fn); } int operator() (int arg) { typedef std::list ::iterator iterator; for (iterator it = functions_m.begin(); it != functions_m.end(); ++it) { UnaryFunction* fnc = *it; // Get particular function arg = (*fnc)(arg); // Apply it on argument } return arg; } private: std::list functions_m; }; Parametrizace functoru probíhá přidáváním unárních funkcí Aplikací functoru pomocí operátoru () postupně zavoláme všechny obsažené funkce

23 PB161 Použití functorů STL algs, Výjimky, Functor 3.11.2014 23 #include int main() { FunctionCompositor comp; comp.prependFunction(new Adder(10)); comp.prependFunction(new Multiplier(2)); comp.prependFunction(new Adder(-5)); comp.prependFunction(new Adder(2)); int number = 0; std::cin >> number; std::cout << comp(number) << std::endl; } Vytváříme functor comp Vytváříme functor typu Adder (a další) a vkládáme do comp Aplikujeme functor comp

24 PB161 Výjimky (Exceptions) STL algs, Výjimky, Functor 3.11.2014 24

25 PB161 Obsluha chyby – bez výjimek STL algs, Výjimky, Functor 3.11.2014 25 int foo(std::string name) { int status = 0; Person person(name); if (status == 0) { if (person.isValidName()) { cout << "Valid person " << person.getName() << endl; } else status = -1; // signalize problem with name } if (status == 0) { // Still no problem? std::string message; message = "My favourite person is "; message += person.getName(); cout << message << endl; } if (status == 0) { // Still no problem? //... do something else } if (status != 0) { // Some problem? //... report problem, roll back info.... } return status; } Proměnná s hodnotou chyby (0 == OK) Test, zda se nevyskytla chyba V případě chyby nastav status Každý další logický blok kódu obalen testem na OK Vrať informaci o průběhu Udělej něco v reakci na problém

26 PB161 Výjimky – motivace Výskyt situace, kterou je potřeba okamžitě řešit ●nedostatek paměti ●nepovolený přístup do paměti ●dělení nulou Může nastat kdekoli v kódu a může být řešitelné ●uvolníme nepotřebnou paměť a zkusíme znovu ●vypíšeme varování uživateli a nulou dál nedělíme Zároveň ale není praktické mít reagující kód na v každé metodě ●nedostatečná paměť může nastat kdekoli STL algs, Výjimky, Functor 3.11.2014 26

27 PB161 Výjimky - syntaxe Označení oblasti kde zachytávat výjimku ●klíčové slovo try Zachycení výjimky ●klíčové slovo catch ●jeden nebo více bloků ●specifikace objektu výjimky typicky jako reference (Vyvolání výjimky) ●klíčové slovo throw STL algs, Výjimky, Functor 3.11.2014 27 try { // … some code throw std::logic_error("Problem"); // … some code (not executed) } catch (std::logic_error& ex) { // … handle somehow exception cout << ex.what() << endl; }

28 PB161 Výjimky (Exception) - princip 1.V případě výskytu problému se vyvolá výjimka objekt obsahující informaci o problému můžeme vyvolat i vývojář programově (throw) 2.Výjimka postupně “stoupá” volajícími funkcemi (callstack), dokud ji někdo nezachytí 3.Výjimka je zachycena obslužným blokem specifikuje, v jaké části kódu a jaké výjimky zachytávat try/catch blok 4.Na základě výjimky proběhne programová reakce ukončení programu výpis varování uživateli exception handling STL algs, Výjimky, Functor 3.11.2014 28

29 PB161 Ukázka STL algs, Výjimky, Functor 3.11.2014 29 int main() { cout << "Code before exception handling" << endl; try { Person p1("Pepa Novak"); // No problem Person p2(""); p1.print(); p2.print(); } catch (WrongNameExceptionExt& ex) { cout << "WrongNameExceptionEx: " << ex.what(); } cout << "Continuing after block with exception handling"; return 0; } class Person { std::string m_name; public: Person(const std::string name) : m_name(name) { if (m_name.size() == 0) throw WrongNameExceptionExt("Invalid empty name"); } void print() const { cout << m_name << endl; } }; Výjimka vyvolána Výjimka zachycena, obsloužena a zaniká Kód nebude vykonán Program pokračuje 1. 2. 3.

30 PB161 Datový typ výjimky Primitivní datové typy ●např. int, char… ● throw 1; catch (int ex) { } ● throw 'e'; catch (char ex) { } Struktury, třídy ●struktury nebo třídy definované programátorem ● MyStructException ex; throw ex; ● catch (MyStructException& ex) { } Potomci std::exception ●nejčastěji potomci std::logic_error nebo std::runtime_error ● class MyException : public std::logic_error { ● catch (std::logic_error& ex) {} STL algs, Výjimky, Functor 3.11.2014 30

31 PB161 STL algs, Výjimky, Functor 3.11.2014 31 int main() { cout << "Code before exception handling“; try { foo(4); // throw exception cout << "Will not be printed"; } catch (int ex) { cout << "Integer exception: " << ex; } catch (char ex) { cout << "Char exception: " << ex; } catch (MyStructException& ex) { cout << "Struct exception : " << ex.reason; } catch (MyException& ex) { cout << "class MyException : " << ex.what(); } cout << "Continuing after block with EH“; return 0; } #include using std::cout; using std::endl; struct MyStructException { std::string reason; int someValue; }; class MyException : public std::invalid_argument { public: MyException(const std::string& reason = "") : std::invalid_argument(reason) {} }; void foo(int what) { if (what == 1) throw 1; if (what == 2) throw 'e'; if (what == 3) { MyStructException ex; ex.reason = "Just testing"; ex.someValue = -1; throw ex; } if (what == 4) throw MyException("Just testing"); } Vyhazuje různé typy výjimek podle what foo(1) foo(2) foo(3) foo(4)

32 PB161 Standardní výjimky Výjimky jsou vyvolávané ●jazykovými konstrukcemi (např. new ) ●funkcemi ze standardní knihovny (např. STL algoritmy) ●uživatelským kódem (výraz throw ) Základní třída std::exception ● #include ●metoda exception::what() pro získání specifikace důvodu Dvě základní skupiny standardních výjimek ● std::logic_error – chyby v logice programu ●např. chybný argument, čtení za koncem pole… ● std::runtime_error – chyby způsobené okolním prostředím ●např. nedostatek paměti (bad_alloc) ●v konstruktoru můžeme specifikovat důvod ( std::string ) ●http://www.cplusplus.com/reference/std/stdexcept/http://www.cplusplus.com/reference/std/stdexcept/ STL algs, Výjimky, Functor 3.11.2014 32

33 PB161 new a zachycení výjimky STL algs, Výjimky, Functor 3.11.2014 33 // Allocate A object dynamically // If fail, std::bad_alloc exception is thrown A* pTest2 = 0; try { pTest2 = new A(20); pTest2->print(); // no need to test pTest2 != NULL delete pTest2; } catch (std::bad_alloc& ex) { cout << "Fail to allocate memory"; } class A { int m_value; public: A(int value) : m_value(value) {} void print() const {cout << m_value << endl; } };

34 PB161 Vlastní výjimky - třídy STL algs, Výjimky, Functor 3.11.2014 std::exception nemá konstruktor s možností specifikace důvodu (řetězec) Dědíme typicky z logic_error a runtime_error ●mají konstruktor s parametrem důvodu ( std::string ) Nebo jejich specifičtějších potomků ●např. std::invalid_argument pro chybné argumenty 34 http://www.cplusplus.com/reference/std/stdexcept/

35 PB161 Vlastní výjimky - ukázka STL algs, Výjimky, Functor 3.11.2014 35 class WrongNameExceptionExt : public std::invalid_argument { std::string m_wrongName; public: WrongNameExceptionExt(const std::string& reason = "", const std::string name = "") : std::invalid_argument(reason), m_wrongName(name) {} const std::string getName() const { return m_wrongName; } ~WrongNameExceptionExt() throw () {} }; Jméno výjimky rodič výjimky zvolte co nejspecifičtěji Výjimka může nést dodatečné informace dle našich potřeb Konstruktor pro specifikace informací o výjimce. Inicializuje i předka. Můžeme přidat vlastní dodatečné metody Destruktor – nutné pokud máme atributy, které mají také destruktor

36 PB161 Zachycení výjimek – využití dědičnosti Výjimky mohou tvořit objektovou hierachii ●typicky nějací potomci std::exception Při zachytávání můžeme zachytávat rodičovský typ ●nemusíme chytat výjimky podle nejspecifičtějšího typu ●obslužný kód může reagovat na celou třídu výjimek ●např. zachytává výjimku typu std::runtime_error a všechny potomky STL algs, Výjimky, Functor 3.11.2014 36 class MyException : public std::invalid_argument; int main() { try { throw MyException(“Test”); } catch (std::invalid_argument& ex) { cout << “invalid argument : " << ex.what(); } return 0; } Vyvoláme MyException, chytáme invalid_argument

37 PB161 Pořadí vyhodnocování catch klauzulí Dle pořadí v kódu ●pokud je více klauzulí, postupně se hledá klauzule s odpovídajícím datovým typem ●klauzule “výše” budou vyhodnoceny dříve Vhodné řadit od nejspecifičtější po nejobecnější ●nejprve potomci, potom předci ●jinak se pozdější specifičtější nikdy neuplatní Kompilátor nás upozorní warningem ●warning: exception of type 'WrongNameException' will be caught by earlier handler for 'std::logic_error' STL algs, Výjimky, Functor 3.11.2014 37

38 PB161 Pořadí zachycení – ukázka problému STL algs, Výjimky, Functor 3.11.2014 38 class WrongNameExceptionExt : public std::invalid_argument; class Person; int main() { cout << "Code before exception handling" << endl; try { Person p2(""); // Exception WrongNameExceptionExt thrown } catch (std::invalid_argument & ex) { cout << "Exception from group std::logic_error : " << ex.what(); } catch (WrongNameExceptionExt& ex) { cout << "WrongNameExceptionExt: " << ex.what() << " " << ex.getName(); } cout << "Continuing after block with exception handling" << endl; return 0; } Není nikdy provedeno – všechny výjimky WrongNameExceptionExt jsou zachyceny jako std::invalid_argument

39 PB161 Zachycení a znovuposlání výjimky Někdy zjistíme že ji nedokážeme obsloužit ●nebo chceme ještě provést obsluhu jinde Výjimka typicky zaniká na konci bloku catch, který ji zachytí ●pokud neurčíme jinak Výjimku můžeme poslat dál ●do bloku catch umístíme throw bez argumentů ●pošle dál aktuální výjimku STL algs, Výjimky, Functor 3.11.2014 39

40 PB161 Znovuposlání výjimky - ukázka STL algs, Výjimky, Functor 3.11.2014 40 class WrongNameExceptionExt : public std::invalid_argument; class Person; void foo() { try { Person p1("Pepa Novak"); // No problem Person p2(""); // Exception thrown } catch (WrongNameExceptionExt& ex) { cout << "WrongNameExceptionExt: " << ex.what() << endl; throw; // Let it propagate further } int main() { try { foo(); } catch (std::logic_error& ex) { cout << "Exception std::logic_error : " << ex.what(); } return 0; } Výjimka odchycena, ale poslána dál Výjimka znovu zachycena a finálně zpracována. Prázdné jméno způsobí výjimku

41 PB161 Zachycení všech výjimek catch(…) Klauzule catch(…){} zachytí většinu běžných výjimek ●závisí na překladači, někdy i nezotavitelné jako SIGSEGV (VS6) ●není přístup k objektu výjimky V běžném kódu zachytávejte pouze výjimky, které umíte zpracovat ●pokud opravdu nevíte že potřebujete zachytit všechny ●okolní kód může být schopen na výjimku reagovat lépe STL algs, Výjimky, Functor 3.11.2014 41

42 PB161 Zachycení všech výjimek catch(…) V některých případech je naopak velmi vhodné zachytávat všechny výjimky ●výjimky by neměly být propagovány mimo váš modul ●není dána přesná realizace objektu výjimky, záleží na překladači ●kód přeložený jiným může spadnout při ošetření Obalení těla funkce main() ●zabrání neřízenému pádu programu Obalení těla destruktoru ●destruktor by neměl nikdy vyvolat výjimku (kdo by ošetřil?) Obalení těla callback funkce ●výjimka z naší callback funkce jde do kontextu uživatele callbacku STL algs, Výjimky, Functor 3.11.2014 42

43 PB161 catch(…) pro logování Využívá se např. v kombinaci se znovuvyvoláním pro uložení logu o problému STL algs, Výjimky, Functor 3.11.2014 43 int main() { try { foo(); } catch (...) { cerr << " error in " << __FILE__ << __LINE__ ; throw; } return 0; }

44 PB161 Nezachycená výjimka STL algs, Výjimky, Functor 3.11.2014 Může nastat když ●neobsluhujeme výjimky vůbec ●nastane mimo blok s obsluhou výjimky Následuje ukončení programu 44 #include int main() { // 1. Segmentation fault (SIGSEGV) int array[10]; array[100] = 1; // 2. Division by zero (SIGFPE) float result = 10 / 0; // 3. Own uncoght exception throw std::logic_error("Test"); return 0; }

45 PB161 Seznam vyvolávaných výjimek Můžeme specifikovat seznam výjimek, které daná metoda může vyvolat (exception-specification) ●informace pro uživatele metody (co hlídat a zkoušet odchytávat) ●informace pro překladač (možné optimalizace, ale viz. dále) Pokud metoda vyvolá jinou výjimku než deklarovanou ●je zavolána funkce std::unexpected() ●defaultní implementace přeruší program ●můžeme upravit set_unexpected(naše_obslužná_fce) Pozor na odlišnost od Javy! ●u Javy kontroluje překladač (nedovolí vyvolávat jinou výjimku) ●u C++ kontroluje až běhové prostředí ( pomocí unexpected()) Problematické, spíše nepoužívejte ●viz. diskuze http://www.gotw.ca/publications/mill22.htmhttp://www.gotw.ca/publications/mill22.htm ●vývojáře nekontroluje (až za běhu), překladači téměř nepomáhá STL algs, Výjimky, Functor 3.11.2014 45

46 PB161 Seznam vyvolávaných výjimek - ukázka STL algs, Výjimky, Functor 3.11.2014 46 struct MyStructException; class MyException : public std::invalid_argument; void foo(int what) throw(int, MyException) { if (what == 1) throw 1; if (what == 2) throw 'e'; if (what == 3) { MyStructException ex; ex.reason = "Just testing"; ex.someValue = -1; throw ex; } if (what == 4) throw MyException("Just testing"); } // Note: will compile even when foo() // has different exception-specification void foo2(int what) throw(int) { foo(what); } void handleUnexpected () { std::cerr << "unexpected exception thrown"; // throws exception with int type //(allowed in exception-specification) throw -1; //... or e.g., terminate //std::terminate(); } #include using std::cout; using std::endl; int main() { std::set_unexpected(handleUnexpected); cout << "Code before exception handling" << endl; try { foo2(3); // throw MyStructException cout << "Will not be printed"; } catch (int ex) { cout << "Integer exception: " << ex << endl; } catch (MyStructException& ex) { cout << "Struct exception : " << ex.reason; } cout << "Continuing after block with EH"; // We may reset unexpected handler to default std::set_unexpected(std::terminate); return 0; }

47 PB161 Vhodnost použití – opakovaná obsluha chyb Výjimky mohou výrazně omezit podmíněný kód pro obsluhu chyby ●kód s podmínkami obsahuje nejčastěji chybu ●výjimky omezují množství kódu s podmínkami ●musí však být používány správně (viz. zneužívání) Při použití výjimek nemusíme mít kód pro vyhodnocení a předání chyby v každé funkci STL algs, Výjimky, Functor 3.11.2014 47

48 PB161 Vhodnost použití výjimek - konstruktory Chybu v konstruktoru nelze předat návratovou hodnotou ●žádná není ●typicky chybné argumenty Lze řešit nějakou validační metodou “isValid()” ●může být nepohodlné ●musíme testovat každý vytvářený objekt Při chybě v konstruktoru lze vyhodit výjimku ●viz. prázdné jméno u třídy Person ●typicky instance std::invalid_argument nebo její potomek ● throw std::invalid_argument(“Invalid empty name”); STL algs, Výjimky, Functor 3.11.2014 48

49 PB161 Vhodnost použití výjimek - operátory Chyby při použití operátorů ●operátory typicky nevrací chybový status ●návratová hodnota operátoru nemusí být použitelná ●např. operátor sčítání může způsobit přetečení výsledku Některé operátory nastavují “fail” bit ●např. >> a << pro iostream ●může být nutné testovat po každé operaci - nepraktické Při chybě v operátoru lze vyhodit výjimku ●např. při detekci přetečení u sčítání ● throw std::overflow_error(“+ result overflow”); STL algs, Výjimky, Functor 3.11.2014 49

50 PB161 Výjimky pro I/O operátory STL algs, Výjimky, Functor 3.11.2014 50 #include int main() { std::cin.exceptions( std::istream::failbit); try { int i; std::cin >> i; std::cout << "Succesfully read: " << i << std::endl; } catch (std::istream::failure & ex) { std::cout << "Exception: " << e.what() << std::endl; } return 0; } int x; cin >> x; if (cin.fail()) { }

51 PB161 (Ne)vhodnost použití výjimek – dealokace Výjimka může způsobit memory leak ●kód s dealokací díky výjimce neproběhne Lze řešit kombinací zachycení a znovuvypuštění ● catch (…) { delete[] data; throw; } Lze řešit použitím auto_ptr,unique_ptr ●vhodnější, můžeme deklarovat i alokovat v podblocích STL algs, Výjimky, Functor 3.11.2014 51

52 PB161 Zneužívání a nadužívání výjimek STL algs, Výjimky, Functor 3.11.2014 Zachytávání, ale neošetřování výjimek ● catch (…) { /* do nothing */ } ●zachytíme vše a nereagujeme Nadužívání výjimek ●např. nadměrné testování přístupu k poli pomocí at() 52 std::vector myVect(100, 5); float result = 0; for (unsigned int i = 0; i < 10000000; i++) { if (i < myVect.size()) result += myVect[i]; } for (unsigned int i = 0; i < 10000000; i++) { try { result += myVect.at(i); } catch (std::out_of_range& ex) { // do nothing } bez výjimky s výjimkou

53 PB161 Problém s defaultním destruktorem Může nastat při vytváření vlastní výjimky jako potomek exception ●error: looser throw specifier for … ●pozor, ne všechny překladače hlásí Nastává, pokud u třídy výjimky definujeme atributy s vlastním destruktorem ●např. std::string pro uložení dalších informací ●atribut může způsobit vyvolání výjimky, kterou předek v throw deklaraci nespecifikuje Více viz. http://www.agapow.net/programming/cpp/looser- throw-specifier http://www.agapow.net/programming/cpp/looser- throw-specifier STL algs, Výjimky, Functor 3.11.2014 53

54 PB161 Další informace k výjimkám Motivace a pravidla pro vhodnost použití výjimek ●http://www.parashift.com/c++-faq-lite/exceptions.htmlhttp://www.parashift.com/c++-faq-lite/exceptions.html Princip výjimek a vhodnost (např. RAII) ●http://www.gamedev.net/reference/articles/article953.a sphttp://www.gamedev.net/reference/articles/article953.a sp STL algs, Výjimky, Functor 3.11.2014 54

55 PB161 Standardní výjimky bad_alloc – při dynamické alokaci (typicky nedostatek paměti) bad_cast – chybné přetypování bad_exception – vyvolaná výjimka není v seznamu deklarovaných výjimek bad_typeid – výjimka vyvolaná funkcí typeid ios_base::failure – problém STL algs, Výjimky, Functor 3.11.2014 55

56 PB161 Výjimky - ukázky exceptionTypeDemo.cpp ●zachycení výjimek různých typů exceptionDemo.cpp ●zachycení obecnější výjimky před specifičtější (chyba) exceptionReThrowDemo.cpp ●ukázka znovuvyvolání výjimky unhandledException.cpp ●ukázka neošetřené výjimky exceptionSpeedDemo.cpp ●ukázka nadužívání výjimek exceptionSpecifDemo.cpp ●ukázka použití specifikace vyvolávaných výjimek STL algs, Výjimky, Functor 3.11.2014 56

57 PB161 Shrnutí STL Algoritmy ●Velké množství předpřipravených operací nad kontejnery a itearátory Functor ●Objekt využitelný namísto funkčního ukazatele Výjimky jsou nástroj pro usnadnění ošetření chyb ●Společné místo pro ošetření výjimek z většího rozsahu kódu ●Lze využít dědičnosti ●Pozor na nadužívání výjimek STL algs, Výjimky, Functor 3.11.2014 57

58 PB161 Bonus STL algs, Výjimky, Functor 3.11.2014


Stáhnout ppt "PB161 PB161 – Programování v jazyce C++ Objektově Orientované Programování STL algoritmy, Funktory, Výjimky STL algs, Výjimky, Functor 3.11.2014 1."

Podobné prezentace


Reklamy Google