temat 10 - Robert Arsoba
Transkrypt
temat 10 - Robert Arsoba
Materiały dydaktyczne Języki i paradygmaty programowania Wyjątki (obsługa sytuacji wyjątkowych) dr inż. Robert Arsoba [email protected] Koszalin 2012 Wersja 1.0 KIK 2012 Sytuacje wyjątkowe w programach Strona 2 Powody sytuacji wyjątkowych: • błąd w programie • niepoprawne dane wejściowe • niepoprawne działanie sprzętu przyczyny wewnętrzne przyczyny zewnętrzne Języki i paradygmaty programowania Obsługa błędów: • zakończenie programu z komunikatem o błędzie – funkcja exit (kod błędu) • „bezpieczne” zakończenie programu – zapis danych – zwolnienie zasobów (pamięć, pliki, strumienie, itd…) • kontynuacji działania programu – próba naprawienia błędu – próba „obejścia” błędu – rezygnacja z części funkcjonalności programu KIK 2012 Przykłady sytuacji wyjątkowych Strona 3 Przykład 1 Dzielenie przez zero int a = 5; int b = 0; int c; Języki i paradygmaty programowania Rozwiązanie: wykrywanie błędu if (b == 0) // ... c = a / b; Runtime error KIK 2012 Przykłady sytuacji wyjątkowych Strona 4 Przykład 2 Języki i paradygmaty programowania Przepełnienie zmiennej int silnia(unsigned int n) { if (n > 12) Rozwiązanie return 0; unsigned int wynik = 1; for (int i = 1; i <= n; i++ ) wynik = wynik * i; return wynik; } double silnia(unsigned int n) { double wynik = 1; for (int i = 1; i <= n; i++ ) wynik = wynik * i; return wynik; } Błędny wynik obliczeń KIK 2012 Przykłady sytuacji wyjątkowych Strona 5 Przykład 3 Błąd otwarcia pliku FILE *plik; Języki i paradygmaty programowania plik = fopen(”nazwa.txt”, ”r”); if (plik == NULL) { cout << ”Błąd otwarcia pliku” << endl; exit(1); } Rozwiązanie Odczytywanie z nieotwartego pliku KIK 2012 Przykłady sytuacji wyjątkowych Strona 6 Przykład 4 Języki i paradygmaty programowania Brak pamięci int *tablica; int n; cin >> n; tablica = malloc(n*sizeof(int)); if (tablica == NULL) { cout << ”Brak pamięci” << endl; exit(1); } Rozwiązanie tablica = new int[n]; if (tablica == NULL) { cout << ”Brak pamięci” << endl; exit(1); } Odwoływanie się do zabronionego obszaru pamięci KIK 2012 Przykłady sytuacji wyjątkowych Strona 7 Przykład 5 Przekroczenie zakresu int tablica[5]; Języki i paradygmaty programowania for (int i = 0; i < 10; i++) tablica[i] = i; Odwoływanie się do zabronionego obszaru pamięci KIK 2012 Wyjątki w C++ Strona 8 Wyjątkiem (ang. exception) w C++ może być wartość dowolnego typu (prostego, obiektowego, …). Języki i paradygmaty programowania Funkcja, która wykryje błąd i nie obsługuje go (lub nie jest w stanie go obsłużyć) generuje (rzuca) wyjątek. Wygenerowanie (rzucenie) wyjątku powoduje natychmiastowe przerwanie wykonywania funkcji. Funkcja wywołująca może przechwycić (złapać) wyjątek. Nieprzechwycony (niezłapany) wyjątek powoduje przerwanie wykonywania programu – nie należy ignorować wyjątków. KIK 2012 Nowe słowa kluczowe Strona 9 Z wyjątkami związane są następujące polecenia (tzw. klauzulue): try – polecenie, po którym umieszczamy instrukcje, które mogą potencjalnie wygenerować (rzucić) wyjątek Języki i paradygmaty programowania catch – polecenie przechwytujące wyjątek – można używać kilku poleceń catch do łapania wyjątków (sterowanie programem jest przekazywane do polecenia, które odpowiada wygenerowanemu wyjątkowi) throw – polecenie rzucające wyjątek – umożliwia także zadeklarowanie listy wyjątków rzucanych przez funkcję KIK 2012 Przykład Strona 10 Języki i paradygmaty programowania #include <iostream> #include <cstdlib> using namespace std; class liczba { public: liczba(int x = 0) : wartosc(x) { cout << "tworzenie obiektu: " << wartosc << endl; } ~liczba() { cout << "niszczenie obiektu " << wartosc << endl; } private: int wartosc; }; void fun() { liczba a(1); throw 0; // wygenerowanie wyjatku //throw 0.0; // wygenerowanie wyjatku cout << "efekt uruchomienia funkcji" << endl; } KIK 2012 Języki i paradygmaty programowania Przykład Strona 11 int main() { liczba b(2); try { liczba c(3); fun(); cout << "efekt polecenia try" << endl; } catch (double) { cout << "przechwycono double" << endl; } catch (int) { cout << "przechwycono int" << endl; } catch (...) // każdy wyjątek { cout << "przechwycono COŚ" << endl; } cout << "efekt dzialania main" << endl; return 0; } Przed kaluzulami catch wywołane zostaną destruktory tworzenie obiektu 2 tworzenie obiektu 3 tworzenie obiektu 1 niszczenie obiektu 1 niszczenie obiektu 3 przechwycono int efekt działania main KIK 2012 Przykład – nieprzechwycone wyjątki Strona 12 Nieprzechwycenie wyjątku powoduje wywołanie funkcji systemowej terminate(), która następnie wywołuje funkcję abort(). Definiowanie własnej funkcji terminate: Języki i paradygmaty programowania namespace std { typedef void (*terminate_handler)(void); terminate_handler set_terminate(terminate_handler NaszTerminate); } void NaszTerminate() { std::cerr << "zatrzymanie programu" << std::endl; exit(1); Własna funkcja terminate musi kończyć się } wywołaniem funkcji exit lub abort. main() { std::set_terminate(NaszTerminate); throw 0; } KIK 2012 Deklaracja wyjątków rzucanych przez funkcję Strona 13 void funkcja1() throw() { } // nie rzuca żadnych wyjątków void funkcja2() throw(exception) { } Języki i paradygmaty programowania void funkcja3() { } // rzuca wyjątki tylko ze // standardowej hierarchii // rzuca dowolne wyjątki Jeżeli funkcja rzuca wyjątek, który nie został zadeklarowany na liście wyjątków w nagłówku funkcji, to wywołana zostaje funkcja systemowa unexpected(), która domyślnie wywołuje abort(). Definiowanie własnej funkcji unexpected: void unexpected_handler() { throw 0; // np. rzucanie int }; std::set_unexpected(unexpected_handler); KIK 2012 Hierarchia wyjątków Strona 14 Języki i paradygmaty programowania Hierarchia klas wyjątków w bibliotece standardowej KIK 2012 Korzystanie z hierarchii wyjątków Strona 15 Nieprzechwycenie wyjątku powoduje wywołanie funkcji systemowej terminate(), która następnie wywołuje funkcję abort(). main() { try { Języki i paradygmaty programowania throw domain_error(); } catch(invalid_argument &e) { cout << e.what() << endl; } Wykonywana jest pierwsza klauzula catch, która pasuje do wygenerowanego wyjątku Wyjątki należy przechwytywać przez referencję. catch(logic_error &e) { cout << "logic " << e.what() << endl; } catch(exception &e) { cout << "jakis wyjatek " << e.what() << endl; } } KIK 2012 Wyjątki Strona 16 Z przymrużeniem oka… czyli po co jest try i catch? „Błądzić jest rzeczą ludzką.” (Seneka Starszy) „Błędów nie popełnia ten, kto nic nie robi.” (Theodore Roosevelt) Języki i paradygmaty programowania „Najczęstszy ludzki błąd – nie przewidzieć burzy w piękny czas.” (Niccolo Machiavelli) „Prawdziwym błędem jest błąd popełnić i nie naprawić go.” (Konfucjusz) „Popełniaj błędy i naprawiaj je” (Myslovitz: „Acidland”) „Najlepszych ludzi uformowało naprawianie własnych błędów.” (William Shakespeare) „Żył jako błąd, poprawiony umarł.” (Andrzej Coryell) „Najwyższą formą zaufania jest kontrola.”