Programování v C++ 1, 17. cvičení výjimky 1 1 Fakulta jaderná a fyzikálně inženýrská České vysoké učení technické v Praze Zimní semestr 2018/2019
Přehled 1 2
Shrnutí minule procvičené látky Binární vyhledávací strom strom typu T pravidlo uspořádání vrcholů ve stromu zpracování stromu přímé zpracování vnitřní zpracování pozdní zpracování základní operace se stromem: vložení vrcholu do stromu tisk dat uložených ve vrcholech zrušení stromu vyhledání vrcholu odstranění vrcholu
Rozbor domácího úkolu Zadání Do šablony List doplňte následující metody, které budou implementovat třídění přímým výběrem: 1 Item<T>* List<T>::findMinimum(Item<T> *i) pro nalezení prvku s nejmenší hodnotou za prvkem i 2 void List<T>::swap(Item<T> *a, Item<T> *b) pro prohození prvků a a b 3 void List<T>::sort() pro seřazení seznamu.
Třídění seznamu Algoritmus třídění přímým výběrem Máme spojový seznam s N prvky, potom pro všechny i=1, 2,..., N - 1 1 V 1. kroku najdeme nejmenší prvek v celém seznamu a prohodíme jeho obsah s obsahem 1. prvku. Získáme setříděnou část seznamu délky 1. 2 Ve 2. kroku najdeme nejmenší prvek v části seznamu začínající druhým prvkem a prohodíme jeho obsah s obsahem 2. prvku. Získáme setříděnou část seznamu délky 2. 3 V i. kroku najdeme nejmenší prvek v části seznamu začínající i. prvkem a prohodíme jeho obsah s obsahem i-tého. prvku. Získáme setříděnou část seznamu délky i.
Řešení 1 template<typename T> 2 Item<T>* List<T>::findMinimum(Item<T> *p){ 3 Item<T> *min = p; 4 while(p!=last){ 5 if(p->getdata() < min->getdata()) 6 min = p; 7 p = p->next; 8 } 9 return min; 10 } 11 12 template<typename T> 13 void List<T>::swap(Item<T> *pa, Item<T> *pb){ 14 T c = pa->getdata(); 15 pa->setdata(pb->getdata()); 16 pb->setdata(c); 17 }
Vlastní třídění 1 template<typename T> 2 void List<T>::sort(){ 3 Item<T> *p = first->next; 4 Item<T> *min; 5 //pro vsechny prvky od druheho po posledni 6 while(p!=last){ 7 //najdi minimum 8 min = findminimum(p); 9 if(min!=p) //prohod 10 this->swap(min, p); 11 p = p->next; 12 } 13 }
v C++ pouze v C++ (v C strukturované výjimky rozšíření MS) výjimka je běhová chyba při vzniku výjimky nemůže program normálním způsobem pokračovat v C++ synchronní výjimky vznikají v programu ošetření chyby: kde vznikla? běhová chyba jako důsledek logické chyby vzniklé na jiném místě programu pro ošetření chyby potřeba dostat se na místo jejího vzniku výjimky umožňují snadno, rychle a bezpečně přejít na jiné místo v programu a také umožňují přenést z místa vzniku chyby informace potřebné k jejímu ošetření výjimky podporovány překladači od poloviny 90. let
Chráněný blok operace, které mohou vyvolat vznik výjimky, do chráněného bloku: pokusný blok handler(y) pokud v pokusném bloku nevznikne výjimka, provedou se všechny v něm uvedené příkazy a řízení pokračuje prvním příkazem za hlidaným blokem pokud v pokusném bloku vznikne výjimka, řízení se v místě vzniku výjimky přeruší a pokračuje některým z handlerů pokud příslušný handler neukončí program, řízení pokračuje za hlídaným blokem při vzniku výjimky se hledá vhodný handler, který by ji ošetřil; pokud se nenajde v bloku, kde vznikla, pokračuje hledání v nadřazeném bloku šíření výjimky neošetřená výjimka
Syntaxe Chráněný_blok pokusný_blok seznam_handlerů Pokusný_blok try složený_příkaz Seznam_handlerů handler seznam_handlerů nep Handler catch(deklarace_výjimky) složený_příkaz Deklarace_výjimky analogické specifikaci jednoho formálního parametru funkce
Vyvolání výjimky k vyvolání výjimky slouží příkaz throw Výraz_throw throw přiřazovací_výraz nep hodnota přiřazovacího výrazu nese informaci o výjimce tuto hodnotu lze v handleru použít k ošetření výjimky typ výjimky dán typem přiřazovacího výrazu zavolání příkazu throw ukončí pokusný blok a způsobí přenos řízení do nejbližšího handleru pro daný typ výjimky pokud se ve funkci, kde vznikla výjimka, nenajde odpovídající handler, funkce se ukončí a handler se bude hledat v nadřazeném bloku
Specifikace výjimek v deklaraci funkce výjimky se šíří po blocích možnost definovat, které výjimky se můžou šířit z funkce: Deklarace_funkce_se_specifikací_výjimek hlavička_funkce hlavička_funkce noexcept Příklady: 1 void f(); z těla f se může šířit výjimka libolného typu 2 void g() noexcept; z těla g se nesmí šířit žádná výjimka neočekávaná výjimka
Třída ListException 1 #ifndef LISTEXCEPTION_H_INCLUDED 2 #define LISTEXCEPTION_H_INCLUDED 3 4 #include <exception> 5 #include <string> 6 #include <iostream> 7 8 using namespace std; 9 10 class ListException : public exception{ 11 string message; 12 public: 13 ListException(string msg) : message(msg){} 14 virtual const char* what() const noexcept{ 15 return message.c_str(); 16 } 17 }; 18 19 #endif // LISTEXCEPTION_H_INCLUDED
Příklad: vyjmutí posledního prvku seznamu 1 zarážku přesuň na předchozí prvek 2 původní zarážku odstraň ze seznamu 3 do položky další nové zarážky ulož nulový ukazatel 4 vrat data z nové zarážky 1 template<typename T> 2 T List<T>::pop_back(){ 3 if(empty()) 4 throw ListException("Nelze vybirat 5 z prazdneho seznamu"); 6 last = last->prev; 7 delete last->next; 8 last->next = nullptr; 9 return last->getdata(); 10 }
Použití chráněného bloku 1 int main(){ 2 try{ 3 List<int> s; 4 cout << "1. hlaseni z pokusneho bloku" << endl; 5 cout << s.pop_back() << endl; 6 cout << "2. hlaseni z pokusneho bloku" << endl; 7 s.push_back(5); 8 s.sort(); 9 } 10 catch(listexception &e){ 11 cout << e.what() << endl; 12 } 13 cout << "Toto uz je za handlerem" << endl; 14 return 0; 15 }
Ošetření vytvoření prvku první přístup Použití operátoru new s parametrem nothrow: 1 template<typename T> 2 void List<T>::push_back(T d){ 3 last->setdata(d); 4 Item<T> *tmp = new(nothrow) Item<T>(); 5 if(tmp){ 6 last->next = tmp; 7 tmp->prev = last; 8 last = tmp; 9 } else{ 10 throw ListException("Nelze alokovat 11 pamet pro novy prvek"); 12 } 13 }
Ošetření vytvoření prvku druhý přístup Použití operátoru new bez parametru nothrow: 1 template<typename T> 2 void List<T>::push_front(T d){ 3 try{ 4 first->setdata(d); 5 Item<T> *tmp = new Item<T>(); 6 first->prev = tmp; 7 tmp->next = first; 8 first = tmp; 9 } 10 catch(bad_alloc &e){ 11 throw ListException("Nelze alokovat 12 pamet pro novy prvek"); 13 } 14 }
Univerzální handler handlerů může být v chráněném bloku více vhodný handler se prohledává v seznamu odshora využití dědičnosti handler exception zachytí výjimky třídy exception a její potomky zachytí všechny standardní výjimky konkrétní typy by měly být v seznamu handleru uvedeny nahoře univerzální handler zápis jako výpustka:... zachytí výjimky všech typu musí být uveden jako poslední propadnutí do univerzálního handleru znamená většinou opomenutí ošetření nějaké výjimky
Shrnutí 1 Šablona seznamu dokončení třídění přímým výběrem 2 Synchronní výjimky v jazyce C++ synchronní výjimka jako běhová chyba vzniklá v programu chráněný blok pokusný blok handlery vyvolání výjimky: příkaz throw šíření výjimek šíření informace o chybě neošetřená výjimka univerzální handler