25
Wyjątki Wyjątki

Wyjątki

  • Upload
    burt

  • View
    38

  • Download
    0

Embed Size (px)

DESCRIPTION

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 być używany na różny sposób, nie jesteśmy w stanie przewidzieć jak zareagować na błąd. - PowerPoint PPT Presentation

Citation preview

Page 1: Wyjątki

WyjątkiWyjątki

Page 2: Wyjątki

Po co nam wyjątki?Po co nam wyjątki?

Często pisząc jakiś kod staramy się go uczynić Często pisząc jakiś kod staramy się go uczynić uniwersalnym, jesteśmy w stanie wykryć uniwersalnym, jesteśmy w stanie wykryć sytuacje niepoprawne, ale nasz kod może być sytuacje niepoprawne, ale nasz kod może być używany na różny sposób, nie jesteśmy w używany na różny sposób, nie jesteśmy w stanie przewidzieć jak zareagować na błąd. stanie przewidzieć jak zareagować na błąd.

Ze strony kogoś korzystającego z Ze strony kogoś korzystającego z danej danej biblioteki sytuacja odwrotna – wiadomo jak biblioteki sytuacja odwrotna – wiadomo jak obsłużyć, aobsłużyć, alele nie nie wiadomo jak wiadomo jak wykryć.wykryć.

Page 3: Wyjątki

Wyjątki w C++Wyjątki w C++ W C++ wprowadzono mechanizm wyjątków, W C++ wprowadzono mechanizm wyjątków, jako jako

sposób na zgłaszanie sposób na zgłaszanie bbłędów w momencie ich łędów w momencie ich wykrycia i wykrycia i na na definiowanie zachowania programu w definiowanie zachowania programu w przypadku pojawienia się błędów. Obsługa wyjątków przypadku pojawienia się błędów. Obsługa wyjątków realizowana jest w C++ z użyciem słów kluczowych realizowana jest w C++ z użyciem słów kluczowych catch throwcatch throw i i trytry.. throwthrow — zgłoszenie wyjątku — zgłoszenie wyjątku trytry — poprzedza blok instrukcji (obowiązkowo w — poprzedza blok instrukcji (obowiązkowo w

nawiasach klamrowych) w którym można spodziewać się nawiasach klamrowych) w którym można spodziewać się wystąpienia wyjątkówwystąpienia wyjątków

catchcatch — definiuje reakcję na wystąpienie wyjątku (też — definiuje reakcję na wystąpienie wyjątku (też obowiązują nawiasy).obowiązują nawiasy).

Page 4: Wyjątki

throw, try i catchthrow, try i catch

double funkcja()double funkcja() // funkcja która o niepowodzeni// funkcja która o niepowodzeniuu //// swoich obliczeń swoich obliczeń informuje informuje // // zgłzgłaszając aszając wyjątwyjątekek{{ // // pewne pewne obliczeniaobliczenia // // w razie wykrycia w razie wykrycia błędubłędu throw 1; throw 1; // zgłoszenie wyjątku// zgłoszenie wyjątku // // w przeciwnym przypadku w przeciwnym przypadku dalsze obliczeniadalsze obliczenia // // wykryto wykryto inny błądinny błąd throw 2; throw 2; // zgłoszenie innego wyjątku// zgłoszenie innego wyjątku // ...// ...}}

Page 5: Wyjątki

void przykl0() void przykl0() {{ trytry // wykonujemy operacje, przewidujemy // 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 << „cout << „bez błędów :-) bez błędów :-) ";"; }} catch (int i) catch (int i) // w przypadku zgłoszenia wyjątku // 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.: // (do tzw.: procedury obsługi wyjątkuprocedury 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 // dal// dalssze instrukcjeze instrukcje cout << „cout << „koniec przykladu 0 koniec przykladu 0 ";";}}

Page 6: Wyjątki

throw, try i catchthrow, try i catch throwthrow – jest operatorem, po nim – jest operatorem, po nim następuje następuje wyrażenie wyrażenie

które określi rodzaj wyjątku, mogą być różne które określi rodzaj wyjątku, mogą być różne typy/klasy wyjątkówtypy/klasy wyjątków;;

catchcatch – może pojawić się tylko po try lub po innym – może pojawić się tylko po try lub po innym catch, w nawiasie określamy typ wyjątku i catch, w nawiasie określamy typ wyjątku i zmienną/obiekt która przekazuje informacje o zmienną/obiekt która przekazuje informacje o wyjątku. wyjątku. Jeżeli do obsługo błędu wystarczy sam fakt jego wykrycia Jeżeli do obsługo błędu wystarczy sam fakt jego wykrycia

to podajemy typ nie podając zmiennej/obiektu. to podajemy typ nie podając zmiennej/obiektu. BBlok po catch nazywamy procedurą obsługi wyjątkulok po catch nazywamy procedurą obsługi wyjątku.. Procedura obsługi wyjątku może znajdować się w tej samej Procedura obsługi wyjątku może znajdować się w tej samej

funkcji w której następuje zgłoszenie wyjątkufunkcji w której następuje zgłoszenie wyjątku..

Page 7: Wyjątki

void przykl1()void przykl1(){{ trytry {{ // 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"; }}}}

Page 8: Wyjątki

Obsługa zgłoszenia wyjątkuObsługa zgłoszenia wyjątku

W momencie wykrycia wyjątku przeglądany jest stos W momencie wykrycia wyjątku przeglądany jest stos od funkcji w której zgłoszono wyjątek przez łańcuch od funkcji w której zgłoszono wyjątek przez łańcuch wywołań funkcji aż do main(). wywołań funkcji aż do main(). Przy wychodzeniu „w górę” wykonywane są destrukcje Przy wychodzeniu „w górę” wykonywane są destrukcje

obiektów lokalnych (tak jak przy normalnym opuszczeniu obiektów lokalnych (tak jak przy normalnym opuszczeniu funkcji). funkcji).

Jeżeli nie napotka się nigdzie procedury obsługi Jeżeli nie napotka się nigdzie procedury obsługi zgłoszonego wyjątku (może być ich więcej niż jedna) to zgłoszonego wyjątku (może być ich więcej niż jedna) to nastąpi przerwanie programu. nastąpi przerwanie programu.

Jeżeli jest kilka na różnych poziomach zagnieżdzenia Jeżeli jest kilka na różnych poziomach zagnieżdzenia (wywołań funkcji) to wykonana zostanie najwcześniej (wywołań funkcji) to wykonana zostanie najwcześniej znaleziona, czyli ta którą sterowanie minęło jako ostatnią.znaleziona, czyli ta którą sterowanie minęło jako ostatnią.

Page 9: Wyjątki

Obsługa zgłoszenia wyjątkuObsługa zgłoszenia wyjątku

void przykl2()void przykl2(){{ trytry {{ 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 }}}}

Page 10: Wyjątki

Ponowne zgłoszenie wyjątkuPonowne zgłoszenie wyjątku Wyjątek jest uznawany obsłużony w momencie rozpoczęcia wykonywania 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:procedury obsługi wyjątku — następujący kod nie powoduje zapętlenia:

trytry { { // pwoduje wystąpienie wyjątku klasy xxx// pwoduje wystąpienie wyjątku klasy xxx }} catch (catch (ExType ExType xxx)xxx) {{ // nieudana próba naprawy// nieudana próba naprawy throw xxx; throw xxx; // pójdzie „w górę” do kodu który wywołał ten// pójdzie „w górę” do kodu który wywołał ten }}

OOperator throw bez argumentu w procedurze obsługi wyjątku powoduje perator throw bez argumentu w procedurze obsługi wyjątku powoduje ponowne jego zgłoszenie.ponowne jego zgłoszenie.

Tutaj Tutaj zamiast „throw xxx;” wystarczyłoby napisać „throw;”zamiast „throw xxx;” wystarczyłoby napisać „throw;”..

Page 11: Wyjątki

Zagnieżdzanie procedur obsługiZagnieżdzanie procedur obsługitrytry{ { // kod, który może zgłosić wyjątek klasy zzz// kod, który może zgłosić wyjątek klasy zzz}}catch (zzz)catch (zzz){{ try try // próbujemy coś zrobić z wyjątkiem// 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; throw; // znaczy to samo co „throw zzz;”, // 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 }}}}

Page 12: Wyjątki

Klasy wyjątkówKlasy wyjątków

Można zdefiniować wiele klas wyjątków, albo do Można zdefiniować wiele klas wyjątków, albo do opisu wyjątku wykorzystać istniejące już typy/klasyopisu wyjątku wykorzystać istniejące już typy/klasy..

WW bibliotekach klas korzystających z wyjątków bibliotekach klas korzystających z wyjątków zazwyczaj zazwyczaj korzysta się ze specjalnych klas do korzysta się ze specjalnych klas do określania rodzaju wyjątków. określania rodzaju wyjątków.

Stosowanie klas jako typów wyjątków jest wygodne, Stosowanie klas jako typów wyjątków jest wygodne, możemy tworzyć klasy o nazwach opisujących typy możemy tworzyć klasy o nazwach opisujących typy wyjątków, wyjątków,

Page 13: Wyjątki

Klasy wyjątkówKlasy wyjątków PrzykładPrzykład: klasa błędu: dielenie przez zero: klasa błędu: dielenie przez zero

class błąd_dzielenia_przez_0 {};class błąd_dzielenia_przez_0 {};

w razie potrzeby zgłoszenia wyjątku korzystamy z konstruktoraw razie potrzeby zgłoszenia wyjątku korzystamy z konstruktora

throw błąd_dzielenia_przez_0();throw błąd_dzielenia_przez_0();

i wyłapujemy wyjątek:i wyłapujemy wyjątek:

catch (błąd_dzielenia_przez_0) { catch (błąd_dzielenia_przez_0) { /* ... *//* ... */ } }

W powyższym przykładzie skorzystaliśmy z klasy (a nie z obiektu, przez W powyższym przykładzie skorzystaliśmy z klasy (a nie z obiektu, przez konstruktory parametrowe możemy również przekazywać obiekty o konstruktory parametrowe możemy również przekazywać obiekty o istotnej wartości)istotnej wartości)

Page 14: Wyjątki

Dziedziczenie klas wyjątkówDziedziczenie klas wyjątków

Przy obsłudze klas wyjątków możemy również Przy obsłudze klas wyjątków możemy również skorzystać z dziedziczenia – procedura obsługi skorzystać z dziedziczenia – procedura obsługi wyjątku klasy bazowej obsłuży wyjątek klasy wyjątku klasy bazowej obsłuży wyjątek klasy pochodnej (pochodnej (niejawna konwersja automatyczna niejawna konwersja automatyczna – ale – ale uwagauwaga:: tylko dziedziczącej klasę bazową publicznie). tylko dziedziczącej klasę bazową publicznie).

class blad_matematyczny {};class blad_matematyczny {};class nadmiar:public blad_matematyczny {};class nadmiar:public blad_matematyczny {};class niedomiar:public blad_matematyczny {};class niedomiar:public blad_matematyczny {};class dzielenie_przez_0:public blad_matematyczny {};class dzielenie_przez_0:public blad_matematyczny {};

Page 15: Wyjątki

Jeżeli jest kilka procedur obsługi wyjątku mogących obsłużyć Jeżeli jest kilka procedur obsługi wyjątku mogących obsłużyć dany wyjątek, to zostanie wykonana pierwsza (najbliższa dany wyjątek, to zostanie wykonana pierwsza (najbliższa bloku try) z nich.bloku try) z nich.

trytry{{ throw nadmiar();throw nadmiar();}}catch(nadmiar) catch(nadmiar) // obsługa nadmiaru i wyjątków klas // obsługa nadmiaru i wyjątków klas {{ // // pochodnych od nadmiarpochodnych od nadmiar cout << "\nnadmiar";cout << "\nnadmiar";}}catch(blad_matematyczny) catch(blad_matematyczny) // obsługa błędów matematycznych i jego // obsługa błędów matematycznych i jego {{ // pochodnych , za wyjątkiem już obsłużonego// pochodnych , za wyjątkiem już obsłużonego cout << "\nbm"; cout << "\nbm"; // nadmiaru i wyjątków // nadmiaru i wyjątków } } // klas pochodnych od nadmiar// klas pochodnych od nadmiar

Dziedziczenie klas wyjątkówDziedziczenie klas wyjątków

Page 16: Wyjątki

GGdyby obsługa błędudyby obsługa błędu__matematycznego matematycznego poprzedzała poprzedzała obsługobsługęę nadmiaru to obsługiwała by zawsze nadmiaru to obsługiwała by zawsze równieżrównież nadmiar: nadmiar:

trytry{{ throw nadmiar();throw nadmiar();}}catch(blad_matematyczny) catch(blad_matematyczny) // obsługa błędów matematycznych// obsługa błędów matematycznych{{ // // i jego pochodnych i jego pochodnych klasy klasy blad_matematycznyblad_matematyczny cout << "\nbm";cout << "\nbm";}}catch(nadmiar) catch(nadmiar) // obsługa nadmiaru i wyjątków klas pochodnych od 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// procedura obsługi wyjątku blad_matematyczny cout << "\nnadmiar";cout << "\nnadmiar";}}

Dziedziczenie klas wyjątkówDziedziczenie klas wyjątków

Page 17: Wyjątki

Obsługa nieobsłużonych wyjątkówObsługa nieobsłużonych wyjątków Za pomocą instrukcji catch(...) tworzymy procedurę Za pomocą instrukcji catch(...) tworzymy procedurę

obsługi wszystkich klas wyjątkówobsługi wszystkich klas wyjątków

void m()void m(){{ trytry {{ // coś// coś }} catch(...)catch(...) {{ // zrób porządki po niedokończonej funkcji// zrób porządki po niedokończonej funkcji throw; throw; // powtórnie zgłoś wyjątek jako sygnał niepowodzenia// powtórnie zgłoś wyjątek jako sygnał niepowodzenia }}}}

Page 18: Wyjątki

Specyfikowanie jawne wyjątków Specyfikowanie jawne wyjątków zgłaszanych przez metodyzgłaszanych przez metody

void void C::metC::met() throw(() throw(intint)){{ // obsolete!// obsolete!

// coś// coś throw(12);throw(12);

// coś// coś}}

void void C::metC::met() throw()() throw()

{{ // obsolete!// obsolete!// coś// coś

// throw zabronione tutaj!// throw zabronione tutaj!// coś// coś

}}

void void C::metC::met() () noexcept(false)noexcept(false){{ // coś// coś throw(12);throw(12); // coś// coś}}

void void C::metC::met() () noexceptnoexcept

{{// coś// coś

// throw zabronione tutaj!// throw zabronione tutaj!// coś// coś

}}

Page 19: Wyjątki

Specyfikowanie jawne wyjątków Specyfikowanie jawne wyjątków zgłaszanych przez metodyzgłaszanych przez metody

funkcja (szablon) może określić kiedy wyrzuca wyjątki za funkcja (szablon) może określić kiedy wyrzuca wyjątki za pomocą specyfikatora noexcept, którego argumentem pomocą specyfikatora noexcept, którego argumentem powinno być stałe wyrażeniepowinno być stałe wyrażenie

void void C::metC::met() () noexcept(sizeof(T)!=sizeof(U));noexcept(sizeof(T)!=sizeof(U));

noexcept jako operator (czasu kompilacji) zwraca true gdy noexcept jako operator (czasu kompilacji) zwraca true gdy jego argument (nie wartościowany) nie wyrzuca wyjątkujego argument (nie wartościowany) nie wyrzuca wyjątku

noexcept(MyClass()); noexcept(MyClass()); // true gdy konstruktor MyClass // true gdy konstruktor MyClass noexcept(f());noexcept(f()); // lub f-kcja f() nie wyrzuca wyjątków // lub f-kcja f() nie wyrzuca wyjątkówvoid void C::metC::met() () noexcept(noexcept(C()));noexcept(noexcept(C()));

Page 20: Wyjątki

Obsługa niespodziewanych Obsługa niespodziewanych wyjątkówwyjątków

set_unexpected (myset_unexpected (my__unexpected)unexpected) ustawia handler obsługi niespodziewanych wyjątkówustawia handler obsługi niespodziewanych wyjątków domyślny handler domyślny handler void unexpected()void unexpected() wywołuje wywołuje terminate()terminate() handler zostanie wywołany gdy wyjątek będzie wyrzucony handler zostanie wywołany gdy wyjątek będzie wyrzucony

niezgodnie ze specyfikacją funkcji wyrzucającejniezgodnie ze specyfikacją funkcji wyrzucającej również handler może wyrzucać wyjątkirównież handler może wyrzucać wyjątki

gdy w jego specyfikacji jest wyjątek gdy w jego specyfikacji jest wyjątek bad_exceptionbad_exception, to wyrzucenie , to wyrzucenie jakiegokolwiek wyjątku niezgodnego ze specyfikacją powoduje jakiegokolwiek wyjątku niezgodnego ze specyfikacją powoduje automatyczne wyrzucenie wyjątku automatyczne wyrzucenie wyjątku bad_exceptionbad_exception

gdy w specyfikacji nie ma wyjątku gdy w specyfikacji nie ma wyjątku bad_exceptionbad_exception, to wyrzucenie , to wyrzucenie jakiegokolwiek wyjątku niezgodnego ze specyfikacją powoduje jakiegokolwiek wyjątku niezgodnego ze specyfikacją powoduje automatyczne wywołanie automatyczne wywołanie terminate()terminate()

Page 21: Wyjątki

Wyjątki a konstruktory i Wyjątki a konstruktory i destruktorydestruktory

listę inicjalizacyjną konstruktora można objąć blokiem listę inicjalizacyjną konstruktora można objąć blokiem try uzywając function try blocktry uzywając function try block

dorosly::dorosly(const dorosly & d) dorosly::dorosly(const dorosly & d)

trytry

:osoba(d), nr_dowodu(aloc_string(d.nr_dowodu)):osoba(d), nr_dowodu(aloc_string(d.nr_dowodu))

{ { // ciało konstruktora// ciało konstruktora

}}

catchcatch (...) (...)

{ { // catch dla konstruktora wyrzuci automatycznie wyjątek jeżeli programista // catch dla konstruktora wyrzuci automatycznie wyjątek jeżeli programista

} } // nie zrobi tego ręcznie, dla funkcji koniec bloku catch oznacza return// nie zrobi tego ręcznie, dla funkcji koniec bloku catch oznacza return

Page 22: Wyjątki

Wyjątki a konstruktory i Wyjątki a konstruktory i destruktorydestruktory

obiekt jest skonstruowany dopiero po opuszczeniu obiekt jest skonstruowany dopiero po opuszczeniu ciała konstruktoraciała konstruktora

wyjątek wyrzucony w liście inicjalizacyjnej wyjątek wyrzucony w liście inicjalizacyjnej spowoduje destrukcję już skonstruowanych spowoduje destrukcję już skonstruowanych składnikówskładników

zgodnie ze standardem destruktor może wyrzucać zgodnie ze standardem destruktor może wyrzucać wyjątki, ale jest to bardzo zły pomysł, bo przede wyjątki, ale jest to bardzo zły pomysł, bo przede wszystkim destruktory są wykonywane podczas wszystkim destruktory są wykonywane podczas obsługi wyjątkówobsługi wyjątków

Page 23: Wyjątki

Wyjątki z biblioteki standardowejWyjątki z biblioteki standardowej

Elementy bibl. standardowej używają wyjątków potomnych po :Elementy bibl. standardowej używają wyjątków potomnych po :

class exception class exception // std::exception // std::exception { public: { public:

exception () throw(); exception () throw(); exception (const exception&) throw(); exception (const exception&) throw(); exception& operator= (const exception&) throw();exception& operator= (const exception&) throw();virtual ~exception() throw(); virtual ~exception() throw(); virtual const char* what() const throw(); virtual const char* what() const throw(); // zwróć opis// zwróć opis

// null-trminated, library implementation dependant// null-trminated, library implementation dependant} }

Page 24: Wyjątki

StandardStandard library library exceptionsexceptions

Elementy bibl. standardowej wyrzucają wyjątki (Elementy bibl. standardowej wyrzucają wyjątki (std::std::) :) :

bad_allocbad_allocwyrzucany przez wyrzucany przez newnew w przypadku niepowodzenia alokacjiw przypadku niepowodzenia alokacji

bad_castbad_cast wyrzucany przezwyrzucany przez dynamic_castdynamic_cast po niepowodzeniu rzutowania referencjipo niepowodzeniu rzutowania referencji

bad_exceptionbad_exceptiongdy nie zaztanie znaleziony pasujący blok catch, lub gdy wyjątek nie gdy nie zaztanie znaleziony pasujący blok catch, lub gdy wyjątek nie odpowiada typom wyspecyfikowanym (oraz jest wyrzucany przez odpowiada typom wyspecyfikowanym (oraz jest wyrzucany przez unexpectedunexpected()()))

bad_typeidbad_typeid wyrzucany przezwyrzucany przez typeidtypeid np. po zastosowaniu do argumentu nullptr np. po zastosowaniu do argumentu nullptr

Page 25: Wyjątki

StandardStandard library library exceptionsexceptions

Elementy bibl. standardowej wyrzucają wyjątki (Elementy bibl. standardowej wyrzucają wyjątki (std::std::) :) :

runtime_errorruntime_errorbaza dle wielu wyjątków tzw. runtime (baza dle wielu wyjątków tzw. runtime (range_error, overflow_error, range_error, overflow_error, underflow_errorunderflow_error))

logic_errorlogic_errorbłąd wewnętrznej logiki programu; baza dle wielu wyjątków błąd wewnętrznej logiki programu; baza dle wielu wyjątków ((domain_error, invalid_argument, length_error, out_of_rangedomain_error, invalid_argument, length_error, out_of_range))

ios_base::failureios_base::failuredla zgłasania błędów przez bibliotekę dla zgłasania błędów przez bibliotekę iostreamiostream

……