Pobieranie prezentacji. Proszę czekać

Pobieranie prezentacji. Proszę czekać

Wyjątki. Po co nam wyjątki? Często pisząc jakiś kod staramy się go uczynić uniwersalnym, jesteśmy w stanie wykryć sytuacje niepoprawne, ale nasz kod może.

Podobne prezentacje


Prezentacja na temat: "Wyjątki. Po co nam wyjątki? Często pisząc jakiś kod staramy się go uczynić uniwersalnym, jesteśmy w stanie wykryć sytuacje niepoprawne, ale nasz kod może."— Zapis prezentacji:

1 Wyjątki

2 Po co nam wyjątki? Często pisząc jakiś kod staramy się go uczynić uniwersalnym, jesteśmy w stanie wykryć sytuacje niepoprawne, ale nasz kod może być używany na różny sposób, nie jesteśmy w stanie przewidzieć jak zareagować na błąd. Często pisząc jakiś kod staramy się go uczynić uniwersalnym, jesteśmy w stanie wykryć sytuacje niepoprawne, ale nasz kod może być używany na różny sposób, nie jesteśmy w stanie przewidzieć jak zareagować na błąd. Ze strony kogoś korzystającego z danej biblioteki sytuacja odwrotna – wiadomo jak obsłużyć, ale nie wiadomo jak wykryć. Ze strony kogoś korzystającego z danej biblioteki sytuacja odwrotna – wiadomo jak obsłużyć, ale nie wiadomo jak wykryć.

3 Wyjątki w C++ W C++ wprowadzono mechanizm wyjątków, jako sposób na zgłaszanie błędów w momencie ich wykrycia i na definiowanie zachowania programu w przypadku pojawienia się błędów. Obsługa wyjątków realizowana jest w C++ z użyciem słów kluczowych catch throw i try. W C++ wprowadzono mechanizm wyjątków, jako sposób na zgłaszanie błędów w momencie ich wykrycia i na definiowanie zachowania programu w przypadku pojawienia się błędów. Obsługa wyjątków realizowana jest w C++ z użyciem słów kluczowych catch throw i try. throw — zgłoszenie wyjątku throw — zgłoszenie wyjątku try — poprzedza blok instrukcji (obowiązkowo w nawiasach klamrowych) w którym można spodziewać się wystąpienia wyjątków try — poprzedza blok instrukcji (obowiązkowo w nawiasach klamrowych) w którym można spodziewać się wystąpienia wyjątków catch — definiuje reakcję na wystąpienie wyjątku (też obowiązują nawiasy). catch — definiuje reakcję na wystąpienie wyjątku (też obowiązują nawiasy).

4 throw, try i catch double funkcja()// funkcja która o niepowodzeniu // swoich obliczeń informuje // swoich obliczeń informuje // zgłaszając wyjątek // zgłaszając wyjątek{ // pewne obliczenia // pewne obliczenia // w razie wykrycia błędu // w razie wykrycia błędu throw 1; // zgłoszenie wyjątku throw 1; // zgłoszenie wyjątku // w przeciwnym przypadku dalsze obliczenia // w przeciwnym przypadku dalsze obliczenia // wykryto inny błąd // wykryto inny błąd throw 2; // zgłoszenie innego wyjątku throw 2; // zgłoszenie innego wyjątku //... //...}

5 void przykl0() { try// wykonujemy operacje, przewidujemy try// wykonujemy operacje, przewidujemy // możliwość zgłoszenia przez nie wyjątku // możliwość zgłoszenia przez nie wyjątku { // klamra obowiązkowa ! { // klamra obowiązkowa ! funkcja(); funkcja(); cout << „bez błędów :-) "; cout << „bez błędów :-) "; } catch (int i) // w przypadku zgłoszenia wyjątku catch (int i) // w przypadku zgłoszenia wyjątku // w bloku po try sterowanie zostanie // w bloku po try sterowanie zostanie // przekazane do bloku instrukcji po catch // przekazane do bloku instrukcji po catch // (do tzw.: procedury obsługi wyjątku) // (do tzw.: procedury obsługi wyjątku) { // klamra obowiązkowa ! { // klamra obowiązkowa ! cout << "wykryto błąd " << i; cout << "wykryto błąd " << i; } // jeżeli funkcja funkcja() zakończy się poprawnie // jeżeli funkcja funkcja() zakończy się poprawnie // (bez zgłaszania wyjątku), to procedura obsługi wyjątku zostanie // (bez zgłaszania wyjątku), to procedura obsługi wyjątku zostanie // pominięta i rozpocznie się wykonywanie dalszych instrukcji // pominięta i rozpocznie się wykonywanie dalszych instrukcji // dalsze instrukcje // dalsze instrukcje cout << „koniec przykladu 0 "; cout << „koniec przykladu 0 ";}

6 throw, try i catch throw – jest operatorem, po nim następuje wyrażenie które określi rodzaj wyjątku, mogą być różne typy/klasy wyjątków; throw – jest operatorem, po nim następuje wyrażenie które określi rodzaj wyjątku, mogą być różne typy/klasy wyjątków; catch – może pojawić się tylko po try lub po innym catch, w nawiasie określamy typ wyjątku i zmienną/obiekt która przekazuje informacje o wyjątku. catch – może pojawić się tylko po try lub po innym catch, w nawiasie określamy typ wyjątku i zmienną/obiekt która przekazuje informacje o wyjątku. Jeżeli do obsługo błędu wystarczy sam fakt jego wykrycia to podajemy typ nie podając zmiennej/obiektu. Jeżeli do obsługo błędu wystarczy sam fakt jego wykrycia to podajemy typ nie podając zmiennej/obiektu. Blok po catch nazywamy procedurą obsługi wyjątku. Blok po catch nazywamy procedurą obsługi wyjątku. Procedura obsługi wyjątku może znajdować się w tej samej funkcji w której następuje zgłoszenie wyjątku. Procedura obsługi wyjątku może znajdować się w tej samej funkcji w której następuje zgłoszenie wyjątku.

7 void przykl1() { try try { // obliczenia i niepowodzenie // obliczenia i niepowodzenie throw ‘a’; throw ‘a’; // dalsze obliczenia i dalsze niepowodzenia // dalsze obliczenia i dalsze niepowodzenia throw 1; throw 1; //... //... } catch (int i) catch (int i) { cout << "wykryto błąd numer " << i; cout << "wykryto błąd numer " << i; } catch (char) catch (char) { cout << "wykryto błąd bez numeru"; cout << "wykryto błąd bez numeru"; }}

8 Obsługa zgłoszenia wyjątku W momencie wykrycia wyjątku przeglądany jest stos od funkcji w której zgłoszono wyjątek przez łańcuch wywołań funkcji aż do main(). W momencie wykrycia wyjątku przeglądany jest stos od funkcji w której zgłoszono wyjątek przez łańcuch wywołań funkcji aż do main(). Przy wychodzeniu „w górę” wykonywane są destrukcje obiektów lokalnych (tak jak przy normalnym opuszczeniu funkcji). Przy wychodzeniu „w górę” wykonywane są destrukcje obiektów lokalnych (tak jak przy normalnym opuszczeniu funkcji). Jeżeli nie napotka się nigdzie procedury obsługi zgłoszonego wyjątku (może być ich więcej niż jedna) to nastąpi przerwanie programu. Jeżeli nie napotka się nigdzie procedury obsługi zgłoszonego wyjątku (może być ich więcej niż jedna) to nastąpi przerwanie programu. Jeżeli jest kilka na różnych poziomach zagnieżdzenia (wywołań funkcji) to wykonana zostanie najwcześniej znaleziona, czyli ta którą sterowanie minęło jako ostatnią. Jeżeli jest kilka na różnych poziomach zagnieżdzenia (wywołań funkcji) to wykonana zostanie najwcześniej znaleziona, czyli ta którą sterowanie minęło jako ostatnią.

9 Obsługa zgłoszenia wyjątku void przykl2() { try try { przykl0(); przykl0(); } catch (int i) catch (int i) { cout << "wykryto błąd numer " << i; cout << "wykryto błąd numer " << i; // ten wyjątek zgłaszany przez funkcja() // ten wyjątek zgłaszany przez funkcja() // jest obsługiwany już w przykl0(), // jest obsługiwany już w przykl0(), // więc ta procedura obsługi wyjątku nie zostanie wykonana // więc ta procedura obsługi wyjątku nie zostanie wykonana }}

10 Ponowne zgłoszenie wyjątku Wyjątek jest uznawany obsłużony w momencie rozpoczęcia wykonywania procedury obsługi wyjątku — następujący kod nie powoduje zapętlenia: Wyjątek jest uznawany obsłużony w momencie rozpoczęcia wykonywania procedury obsługi wyjątku — następujący kod nie powoduje zapętlenia: try try { // pwoduje wystąpienie wyjątku klasy xxx { // pwoduje wystąpienie wyjątku klasy xxx } catch (xxx) catch (xxx) { // nieudana próba naprawy { // nieudana próba naprawy throw xxx; // pójdzie „w górę” do kodu który wywołał ten throw xxx; // pójdzie „w górę” do kodu który wywołał ten } Operator throw bez argumentu w procedurze obsługi wyjątku powoduje ponowne jego zgłoszenie. Operator throw bez argumentu w procedurze obsługi wyjątku powoduje ponowne jego zgłoszenie. Tutaj zamiast „throw xxx;” wystarczyłoby napisać „throw;”. Tutaj zamiast „throw xxx;” wystarczyłoby napisać „throw;”.

11 Zagnieżdzanie procedur obsługi try { // kod, który może zgłosić wyjątek klasy zzz } catch (zzz) { try // próbujemy coś zrobić z wyjątkiem try // próbujemy coś zrobić z wyjątkiem { // próba może się nie powieść, kod naprawy // próba może się nie powieść, kod naprawy // też może zgłosić wyjątek klasy zzz // też może zgłosić wyjątek klasy zzz throw; // znaczy to samo co „throw zzz;”, throw; // znaczy to samo co „throw zzz;”, } catch (zzz) catch (zzz) { // obsługa wyjątku zgłoszonego podczas obsługi wyjątku { // obsługa wyjątku zgłoszonego podczas obsługi wyjątku }}

12 Klasy wyjątków Można zdefiniować wiele klas wyjątków, albo do opisu wyjątku wykorzystać istniejące już typy/klasy. Można zdefiniować wiele klas wyjątków, albo do opisu wyjątku wykorzystać istniejące już typy/klasy. W bibliotekach klas korzystających z wyjątków zazwyczaj korzysta się ze specjalnych klas do określania rodzaju wyjątków. W bibliotekach klas korzystających z wyjątków zazwyczaj korzysta się ze specjalnych klas do określania rodzaju wyjątków. Stosowanie klas jako typów wyjątków jest wygodne, możemy tworzyć klasy o nazwach opisujących typy wyjątków, Stosowanie klas jako typów wyjątków jest wygodne, możemy tworzyć klasy o nazwach opisujących typy wyjątków,

13 Klasy wyjątków Przykład: klasa błędu: dielenie przez zero Przykład: klasa błędu: dielenie przez zero class błąd_dzielenia_przez_0 {}; w razie potrzeby zgłoszenia wyjątku korzystamy z konstruktora w razie potrzeby zgłoszenia wyjątku korzystamy z konstruktora throw błąd_dzielenia_przez_0(); i wyłapujemy wyjątek: i wyłapujemy wyjątek: catch (błąd_dzielenia_przez_0) { /*... */ } W powyższym przykładzie skorzystaliśmy z klasy (a nie z obiektu, przez konstruktory parametrowe możemy również przekazywać obiekty o istotnej wartości) W powyższym przykładzie skorzystaliśmy z klasy (a nie z obiektu, przez konstruktory parametrowe możemy również przekazywać obiekty o istotnej wartości)

14 Dziedziczenie klas wyjątków Przy obsłudze klas wyjątków możemy również skorzystać z dziedziczenia – procedura obsługi wyjątku klasy bazowej obsłuży wyjątek klasy pochodnej (niejawna konwersja automatyczna – ale uwaga: tylko dziedziczącej klasę bazową publicznie). Przy obsłudze klas wyjątków możemy również skorzystać z dziedziczenia – procedura obsługi wyjątku klasy bazowej obsłuży wyjątek klasy pochodnej (niejawna konwersja automatyczna – ale uwaga: tylko dziedziczącej klasę bazową publicznie). class blad_matematyczny {}; class nadmiar:public blad_matematyczny {}; class niedomiar:public blad_matematyczny {}; class dzielenie_przez_0:public blad_matematyczny {};

15 Jeżeli jest kilka procedur obsługi wyjątku mogących obsłużyć dany wyjątek, to zostanie wykonana pierwsza (najbliższa bloku try) z nich. Jeżeli jest kilka procedur obsługi wyjątku mogących obsłużyć dany wyjątek, to zostanie wykonana pierwsza (najbliższa bloku try) z nich.try{ throw nadmiar(); throw nadmiar();} catch(nadmiar) // obsługa nadmiaru i wyjątków klas {// pochodnych od nadmiar cout << "\nnadmiar"; cout << "\nnadmiar";} catch(blad_matematyczny) // obsługa błędów matematycznych i jego { // pochodnych, za wyjątkiem już obsłużonego cout << "\nbm"; // nadmiaru i wyjątków cout << "\nbm"; // nadmiaru i wyjątków } // klas pochodnych od nadmiar Dziedziczenie klas wyjątków

16 Gdyby obsługa błędu_matematycznego poprzedzała obsługę nadmiaru to obsługiwała by zawsze również nadmiar: Gdyby obsługa błędu_matematycznego poprzedzała obsługę nadmiaru to obsługiwała by zawsze również nadmiar:try{ throw nadmiar(); throw nadmiar();} catch(blad_matematyczny) // obsługa błędów matematycznych {// i pochodnych klasy blad_matematyczny cout << "\nbm"; cout << "\nbm";} catch(nadmiar) // obsługa nadmiaru i wyjątków klas pochodnych od nadmiar // nie zostanie nigdy wykorzystana bo te wyjątki obsługuje // nie zostanie nigdy wykorzystana bo te wyjątki obsługuje { // procedura obsługi wyjątku blad_matematyczny cout << "\nnadmiar"; cout << "\nnadmiar";} Dziedziczenie klas wyjątków

17 Obsługa nieobsłużonych wyjątków Za pomocą instrukcji catch(...) tworzymy procedurę obsługi wszystkich klas wyjątków Za pomocą instrukcji catch(...) tworzymy procedurę obsługi wszystkich klas wyjątków void m() { try try { // coś // coś } catch(...) catch(...) { // zrób porządki po niedokończonej funkcji // zrób porządki po niedokończonej funkcji throw; // powtórnie zgłoś wyjątek jako sygnał niepowodzenia throw; // powtórnie zgłoś wyjątek jako sygnał niepowodzenia }}

18 Specyfikowanie jawne wyjątków zgłaszanych przez metody void C::met() throw(int) { // coś throw(12); throw(12); // coś } To nie jest obowiązkowe To nie jest obowiązkowe Ale przyda się programiscie używającemu met() Ale przyda się programiscie używającemu met()

19 Specyfikowanie jawne wyjątków zgłaszanych przez metody void C::met() throw() { // coś // throw zabronione tutaj! // throw zabronione tutaj! // coś }

20 Obsługa niewyspecyfikowanych wyjątków set_unexpected (my_unexpected) set_unexpected (my_unexpected) ustawia handler niewyspecyfikowanych wyjątków ustawia handler niewyspecyfikowanych wyjątków domyślny handler (void unexpected()) wywołuje terminate() domyślny handler (void unexpected()) wywołuje terminate() handler będzie użyty jeżeli wyrzucony wyjątek nie zgadza się ze specyfikacją wyjątków rzucającej funkcji handler będzie użyty jeżeli wyrzucony wyjątek nie zgadza się ze specyfikacją wyjątków rzucającej funkcji jeżeli rzucająca funkcja specyfikuje, że może wyrzucić bad_exception, to powtórne wyrzucenie wyjątku przez handler, albo wyrzucenie innego niewyspecyfikowanego wyjątku, spowoduje automatyczne wyrzucenie wyjątku bad_exception jeżeli rzucająca funkcja specyfikuje, że może wyrzucić bad_exception, to powtórne wyrzucenie wyjątku przez handler, albo wyrzucenie innego niewyspecyfikowanego wyjątku, spowoduje automatyczne wyrzucenie wyjątku bad_exception

21 Wyjątki w bibliotece standardowej Składniki biblioteki standardowej wyrzucają wyjątki klas dziedziczących po: class exception // std::exception { public: exception () throw(); exception (const exception&) throw(); exception& operator= (const exception&) throw(); virtual ~exception() throw(); virtual const char* what() const throw(); // zwróć opis // null-terminated, treść zależna od implementacji biblioteki // null-terminated, treść zależna od implementacji biblioteki}

22 Wyjątki w bibliotece standardowej Składniki biblioteki standardowej wyrzucają wyjątki (std::) : bad_alloc bad_alloc wyrzuca new w przypadku niepowodzenia alokacji bad_cast bad_cast rzuca dynamic_cast gdy nie powiedzie się konwersja referencji bad_exception bad_exception gdy typ wyjątku nie pasuje do żadnego catch, lub do typów wyspecyfikowanych w nagłówku funkcji rzucającej (po wywołaniu unexpected()) bad_typeid bad_typeid rzuca typeid np. gdy otrzyma jako argument NULL rzuca typeid np. gdy otrzyma jako argument NULL

23 Wyjątki w bibliotece standardowej Składniki biblioteki standardowej wyrzucają wyjątki (std::) : runtime_error runtime_error klasa bazowa dla klas definiujących wyjątki czasu wykonania programu (range_error, overflow_error, underflow_error) logic_error logic_error dla błędów wewnętrznej logiki programu; klasa bazowa dla innych (domain_error, invalid_argument, length_error, out_of_range) ios_base::failure ios_base::failure błędy zgłaszane przez bibliotekę iostream …


Pobierz ppt "Wyjątki. Po co nam wyjątki? Często pisząc jakiś kod staramy się go uczynić uniwersalnym, jesteśmy w stanie wykryć sytuacje niepoprawne, ale nasz kod może."

Podobne prezentacje


Reklamy Google