Strona główna » C++ » Kurs » Wyjątki w C++
 

Wyjątki w C++

Wstęp

Podczas wykonywania programu może dojść do sytuacji kiedy wykonanie instrukcji wystąpi błąd. Z reguły w takim momencie następuje przerwanie wykonywania programu. Z reguły dane na wejściu można sprawdzić przy pomocy funkcji if. Taki sposób wykrycia potencjalnych problemów jest wystarczające w przypadku krótkich algorytmów. Dla bardziej skomplikowanych projektów takie rozwiązanie jest mało praktyczne, ponieważ podczas pisania programu trzeba pamiętać co zwraca funkcja w przypadku błędu. Z tego powodu do zgłaszania błędów została stworzona specjalna klauzula try .. catch.

Struktura

Przechwytywanie wyjątku

Przed poznanie struktury na początek warto pojąć idee bloku try .. catch. Przede wszystkim ma ona za zadanie zgłosić wyjątek jeśli program miałby wykonać nieprawidłową operację. Wyjątki mogą być konkretnego typu. Potem taki wyjątek będzie można obsłużyć w dowolnym miejscu w kodzie i będzie można go jednoznacznie zidentyfikować.

  1. try {
  2.   // instrukcje do wykonania
  3. }
  4. catch (exception& e) {
  5. }
  6. // dalsze instrukcje

W celu przechwycenia błędu z określonego ciągu instrukcji należy umieścić je w (1. - 3.) klauzuli try pomiędzy nawiasami klamrowymi. W przypadku, gdy zostanie wykryty błąd w trakcie wykonywania instrukcji to program zwraca wyjątek. Domyślnie jest on typu exception. Wtedy program znajduje odpowiednią klauzulę catch, która obsłuży wyjątek. Obsłużenie może polegać na wypisaniu odpowiedniego komunikatu, albo przekazaniu wyjątku dalej.

Rzucanie wyjątku

W celu rzucenia wyjątku należy użyć słowa kluczowego throw. Po nim można przekazać argument dowolnego typu. Obiekt ten będzie można odczytać w klauzuli catch.

  1. throw [obiekt];

Przykład

Zadanie

Załóżmy, że program wczytuje od użytkownika dwie liczby naturalne a i b. Program ma wypisać na ekran wynik dzielenia a przez b, a jeśli jest to niemożliwe to ma wypisać odpowiedni komunikat. Dzielenie będzie odbywać się w zbiorze liczb naturalnych, dlatego wynikiem dzielenia nie może być ułamek.

Funkcja

Na początek warto napisać funkcję podziel(), która przyjmie dwa całkowitoliczbowe argumenty. Funkcja ma do sprawdzenia dwa warunki: czy dzielnikiem nie jest liczba 0. W obu przypadkach w przypadku niespełnienia program powinien rzucić wyjątek. W tym przypadku przyjmujemy, że zwrócony wyjątek będzie zawierał obiekt, który będzie ciągiem znaków.

  1. int podziel(int a, int b) {
  2.   if (b == 0)
  3.     throw "Dzielnik jest zerem";
  4.   if (a % b != 0)
  5.     throw "Nieprawidlowe dzielenie";
  6.   return a / b;
  7. }

(2.) Sprawdź czy dzielnik jest zerem. Jeśli tak to (3.) rzuć wyjątek. (4. - 5.) Podobna zasada dotyczy jeśli wynikiem miałby być ułamek. Jeśli jednak dzielenie jest prawidłowe to (6.) zwróć jego wynik.

Obsługa

Funkcja main() wczytuje od użytkownika dwie liczby całkowite a i b i jeśli nie zostanie zwrócony wyjątek to wypisuje wynik na ekran.

  1. int main () {
  2.   int a, b;
  3.   cin >> a >> b;
  4.   try {
  5.     int c = podziel(a, b);
  6.     cout << "a/b = " << c;
  7.   }
  8.   catch (const char* msg) {
  9.     cout << msg;
  10.   }
  11.   cout << endl;
  12.   system("pause");
  13.   return 0;
  14. }

(2. - 3.) Wczytaj liczby a i b od użytkownika. (4.) Spróbuj (5.) podzielić liczby i (6.) wypisać wynik na ekran. (8.) Jeśli zostanie zgłoszony jakikolwiek wyjątek to (9.) wypisz komunikat na ekran. Warto zauważyć, że w tym przypadku przechwytywany obiekt błędu msg jest typu const char* msg.

Testowanie funkcji

Istnieją trzy przypadki programu do przetestowania. W przypadku, gdy a jest wielokrotnością b i b jest różne od zera to program powinien wypisać wynik dzielenia np. dla 6 i 3 program wypisze:

  1. a/b = 2

Z kolei jeśli a będzie dowolną liczbą, a b to zero program wypisze komunikat o błędzie. Przykładowy zestaw to 3 i 0.

  1. Dzielnik jest zerem

Ostatni przypadek jest wtedy, gdy a nie jest wielokrotnością b i b jest różne od zera. Wtedy zostanie wypisany drugi komunikat o błędzie. Przykładowo taką parą liczb jest 5 i 2:

  1. Nieprawidlowe dzielenie

Podsumowanie

Obsługa wyjątków umożliwia w bardzo prosty sposób przekazywać informacje pomiędzy funkcjami o wystąpieniu określonego błędu. Należy jednak pamiętać, że powyższy artykuł jest jedynie wstępem do tworzenia i przechwytywania wyjątków w C++. W bardziej zaawansowanych projektach nie zwraca się ciągów tekstu, a specjalne przygotowane obiekty dziedziczące po klasie exception. Powyższa wiedza powinna jednak ułatwić obsługę błędów w prostych algorytmach.

Zadania

Zadanie 1

Napisz funkcję, która wczyta od użytkownika linijkę zawierającą ciąg znaków. Program powinien następnie spróbować przekonwertować wprowadzony tekst na liczbę typu int. W trakcie konwersji program ma prawo zwrócić dwa wyjątki: Wprowadzony ciąg zawiera nieprawidłowe znaki oraz Wprowadzona liczba jest za duża. Na sam koniec program powinien wypisać skonwertowaną liczbę na ekran.

Przykładowo dla 1234 program wypisze liczbę 1234. Z kolei dla 123o4 zostanie zwrócony błąd jak również dla 123.4. Drugi wyjątek powinien się pojawić jeśli wpisana liczba nie mieści się w zakresie typu int.