PO13-1 / 19 Wykład 13 Wyjątki i ich zgłaszanie Wyłapywanie wyjątków Obsługa wyjątków Wykorzystanie polimorfizmu Filtrowanie wyjątków Błędy w konstruktorach Obsługa wyjątków
Wyjątki Wyjątek – nietypowa sytuacja Kod, który napotka błąd, zgłasza wyjątek i tym samym powoduje wyjście z funkcji. Wyjątek jest wyłapywany w funkcji nadrzędnej, czyli tej, która wywołała funkcję, w której wyjątek zgłoszono PO13-2 / 19
Zgłoszenie wyjątku throw konstruktor_klasy_wyjątku(... ); throw exception( ); // wyjątek dowolny throw runtime_error("Dowolny tekst" ); throw bad_alloc("Dowolny tekst" ); throw range_error("Dowolny tekst" ); throw overflow_error("Dowolny tekst" ); Przykłady: Wskazanie na ten tekst daje funkcja what( ) wywołana do utworzonego obiektu klasy wyjątku. Klasy runtime_error, bad_alloc, runge_error, overflow_error pochodzą (bezpośrednio lub pośrednio) od klasy exception i ich konstruktory wymagają podania tekstu w argumencie. PO13-3 / 19
Klasy pochodne od exception exception logic_error bad_alloc runtime_error oveflow_error bad_cast bad_exception ios_base_failure bad_typeid underflow_error range_error length_error invalid_argument domain_error out_of_range PO13-4 / 19
Wyłapywanie wyjątków catch ( const typ_wyjątku zmienna ) { // instrukcje funkcji } catch ( const exception &e ) // dowolny wyjątek bazujący { // na klasie exception cerr << "Przechwycono wyjątek" << endl; exit(1); } Przykłady: Może to być przekazanie: wartości, referencji lub wskaźnika Funkcja wyłapująca wyjątki PO13-5 / 19
Przykłady funkcji catch ( const runtime_error &e ) // wyjątek bazujący na klasie runtime_error { // cerr << "Wyjątek: " << e.what( ) << endl; } Tekst przekazany konstruktorowi w instrukcji throw runtime_error oveflow_error underflow_error range_error PO13-6 / 19
Przykłady funkcji catch (... ); // wyjątek dowolnego typu – mogą to też być // typy: int, char*, itp. { // cerr << "Wyjątek dowolnego typu " << endl; } Przechwytywanie wyjątków dowolnego typu Wyjątki przechwytywane są w kolejności występowania ich typów w funkcjach catch. Powyższa funkcja musi wyłapywać wyjątki jako ostatnia, ponieważ nie pozostawia ona już żadnych wyjątków do wyłapania. PO13-7 / 19
Przykład nieprawidłowy catch ( const runtime_error &e ) { // obsługa wszystkich wyjątków // runtime_error } catch ( const overflow_error &e ) { // obsługa wyjątków // overflow_error } runtime_error oveflow_error underflow_error range_error Wyjątki klasy overflow_error zostały już wyłapane jako wyjątki bazujące na klasie runtime_error PO13-8 / 19
Przykład prawidłowy catch ( const overflow_error &e ) { // obsługa wyjątków // overflow_error } catch ( const runtime_error &e ) { // obsługa pozostałych wyjątków // runtime_error } runtime_error oveflow_error underflow_error range_error D wyłapania pozostały wyjątki klas: - range_error - underflow_error PO13-9 / 19
Obsługa try - catch try { // ciąg instrukcji, które mogą zgłosić wyjątki } catch ( /*parametr*/ ) { //... } catch ( /*parametr*/ ) { //... } //... catch ( /*parametr*/ ) { //... } Jedna lub kilka funkcji wyłapujących wyjątki w zaplanowanej kolejności PO13-10 / 19
int main( ) { try { cout << Podziel( 2.5, 0.5 ) << endl; cout << Podziel( 2.5, 0) << endl; } catch ( exception &e ) { cerr << e.what( ) << endl; } //... Przykład try - catch #include 5 Dzielenie przez zero! double Podziel( double x, double y ) { if(y==0) throw exception("Dzielenie przez zero!"); return x/y; } std::runtime_error("Dzielenie przez zero!"); std::runtime_error &e ) { PO13-11 / 19
Przykład 2 void CzytajVec( char *plik, Vec &v ) { ifstream we(plik, ios::in|ios::nocreate); if(we==0) {string t="Brak pliku"+plik; throw invalid_argument( t ); } we >> v; if(we==0) {string t="Złe dane w pliku"+plik; we.clear( ); throw runtime_error( t ); } PO13-12 / 19
Przykład 2 c.d. int main( ) { Vec W; try{ CzytajVec( "Dane.txt", W ); } catch ( invalid_argument &e ) { cerr << e.what( ) << endl; } catch ( runtime_error &e ) { cerr << e.what( ) << endl; } //... } PO13-13 / 19
Przykład 2 c.d. int main( ) { Vec W; try{ CzytajVec( "Dane.txt", W ); } catch ( exception &e ) { cerr << e.what( ) << endl; } //... } Klasa bazowa obu wyjątków Wywołanie funkcji polimorficznej PO13-14 / 19
Filtrowanie wyjątków void CzytajVec( char *plik, Vec &v ) throw (invalid_argument, runtime_error ) { ifstream we(plik, ios::in|ios::nocreate); if(we==0) {string t="Brak pliku"+plik; we.clear( ); throw invalid_argument( t ); } we >> v; if(we==0) {string t="Złe dane w pliku"+plik; we.clear( ); throw runtime_error( t ); } if(v==0) {throw logic_error( "Zerowy wektor" ); } PO13-15 / 19 Ten wyjątek nie może być zgłoszony. Przerywa wykonanie funkcji CzytajVec i wywołuje funkcję unexpected
Filtrowanie c.d. void CzytajVec( char *plik, Vec &v ) throw ( ) { ifstream we(plik, ios::in|ios::nocreate); if(we==0) {string t="Brak pliku"+plik; we.clear( ); throw invalid_argument( t ); } we >> v; if(we==0) {string t="Złe dane w pliku"+plik; we.clear( ); throw runtime_error( t ); } if(v==0) {throw logic_error( "Zerowy wektor" ); } Te wyjątki nie mogą być zgłoszone. Przerywają wykonanie funkcji CzytajVec i wywołują funkcję unexpected Lista jest pusta. Funkcja nie może zgłaszać żadnych wyjątków. PO13-16 / 19
Błędy w konstruktorach Jeśli wyjątek opuści konstruktor, obiekt nie został poprawnie utworzony i nie zadziała jego destruktor. Destruktory podobiektów zadziałają. Przed zgłoszeniem wyjątku należy „wyczyścić” obiekt, to znaczy wykonać to, co powinien zrobić destruktor - np. zwolnić zaalokowane pamięci. PO13-17 / 19
Przykład Prześledźmy przykładowy konstruktor klasy Tab2, której obiekty dysponują zaalokowaną pamięcią na tablice 2-indeksowe. Niech definicja klasy zawiera: class Tab2{ protected: int W, K;// liczba kolumn i wierszy double **A;// wskaźnik na tablicę //... public: Tab2( int, int ) ; // przykładowy konstruktor //... }; PO13-18 / 19
Przykład c.d. Tab2::Tab2( int W, int K ) throw(bad_alloc) : W(W), K(K) {// W i K to liczba wierszy i kolumn int i=0; try { A = new double*[W+1];// tablica wskaźników for( ; i<W; ++i ) A[i] = new double[K]; // alokacja wierszy } catch(... ) { // wyłapanie dowolnego wyjątku for( int j=0; j<i; ++j ) delete[ ] A[ j ]; delete[ ] A; throw bad_alloc("Brak pamięci!"); } // zgłoszenie wyjątku A[ W ]=0; } PO13-19 / 19