Obsługa wyjątków

Wyjątek - jest to specjalny obiekt zgłaszany przez program, powodujący przerwanie wykonywania danej części kodu

Składnia


Kod, który potencjalnie może zgłosić wyjątek umiejscawiamy w bloku try, zaś obsługę tych wyjątków w następujących zaraz po nim blokach catch:
try
{
 // kod, w którym spodziewamy się rzucenia wyjątku
}
catch (KlasaWyjatku1 kl1)
{
 // w razie rzucenia wyjątku klasy KlasaWyjatku1 wykonany zostanie ten kod
}
catch (KlasaWyjatku2 kl2)
{
 // jak wyżej, ale gdy zostanie rzucony wyjątek klasy KlasaWyjatku2
}


Zgłaszanie (rzucanie) wyjątków


Do zgłaszania wyjątków służy słowo kluczowe throw
throw wyjatek;


Warto wiedzieć, że nie musimy w ten sposób rzucać obiektów klas. Równie dobrze możemy posłużyć się typem wbudowanym:
throw (unsigned long) 0xDEADBEEF;


Hierarchia wyjątków


Przesłanką przemawiającą za rzucaniem obiektów klas jest możliwość stworzenia hierarchii wyjątków. Wynika to stąd, że bloki catch są w stanie łapać obiekty swojej klasy lub klasy pochodnej.
W celu zilustrowania tej właściwości przedstawmy następujący przykład (nazwy klas bardzo obrazowe):

     
  • Mamy klasę o nazwie Wypadek:
     
       class Wypadek
       {
         // Treść nieistotna
       };
       

     
  • Tworzymy klasy o nazwie WypadekKolejowy i WypadekSamochodowy dziedziczące z klasy Wypadek:
     
       class WypadekKolejowy : public Wypadek
       {
         // ...
       };
       class WypadekSamochodowy : public Wypadek
       {
         // ...
       };
       

     
  • Dodatkowo definiujemy klasę Karambol dziedziczącą z klasy WypadekSamochodowy:
     
       class Karambol : public WypadekSamochodowy
       {
         // ...
       };
       



Przykładowy kod przyjmijmy taki:
try
 {
  throw Karambol();
 }
 catch (Karambol w)
 {
  std::cout << "Złapano obiekt >>Karambol<<\n";
 }
 catch (WypadekSamochodowy w)
 {
  std::cout << "Złapano obiekt >>WypadekSamochodowy<<\n";
 }
 catch (Wypadek w)
 {
  std::cout << "Złapano obiekt >>Wypadek<<\n";
 }
 catch (...)
 {
  std::cout << "Złapał catch(...)!\n";
 }


W takim wypadku, jeżeli zgłosimy Karambol
throw Karambol();

wyjątek ten zostanie przechwycony przez blok:
catch (Karambol w)
 {
  std::cout << "Złapano obiekt >>Karambol<<\n";
 }

Jeżeli natomiast zgłosimy WypadekSamochodowy, zostanie on przechwycony przez drugi blok.

Powstaje teraz pytanie: co się stanie, jak w bloku try znajdzie się taki kod:
throw WypadekKolejowy();


Nie ma w naszym kodzie bloku catch odpowiedzialnego za łapanie tego typu obiektów. Wypadek kolejowy jest jednak szczególnym rodzajem wypadku - tak samo u nas WypadekKolejowy jest klasą pochodną od Wypadek. Wyjątek zostanie zatem przechwycony przez blok:
catch (Wypadek w)
 {
  std::cout << "Złapano obiekt >>Wypadek<<\n";
 }

Na takiej samej zasadzie, jeżeli usuniemy blok odpowiedzialny za łapanie Karambolu, łapać takie wyjątki będzie blok:
catch (WypadekSamochodowy w)
 {
  std::cout << "Złapano obiekt >>WypadekSamochodowy<<\n";
 }


Blok catch(...)


W przykładzie powyżej przemycono blok catch z wielokropkiem. Zadanie takiego bloku to: "cokolwiek by nie leciało, łap to!" - blok taki będzie wychwytywał wszystkie nieprzechwycone wcześniej wyjątki.
Przykładowo, jeżeli w naszym bloku try rzucimy obiekt typu char:
throw 'Q';

wyjątek ten zostanie przechwycony przez ostatni blok catch.

Kolejność bloków catch


Kolejność łapania wyjątków nie jest dowolna. Następujący kod:

catch (Wypadek w) { }
 catch (WypadekSamochodowy w) { }

spowoduje błąd. Zasada definiowania bloków catch jest następująca:
Wyjątki należy przechwytywać zaczynając od najbardziej szczegółowych, a kończąc na najbardziej ogólnych.
Z powyższego wynika zatem, że blok catch(...) musi być zawsze ostatnim.

Uwagi



     
  • Bloki try...catch można zagnieżdżać. Nie stanowi to problemu, aby wewnątrz bloku try znalazła się cała konstrukcja try...catch.
     
  • Niezłapane wyjątki powodują zakończenie wykonywania programu i wypisanie komunikatu o błędzie.
     
  • Nie należy rzucać wyjątków z destruktorów! Zignorowanie tego faktu może powodować nieoczekiwane zakończenia wykonywania programu.
     
  • Nie powinno się wyrzucać wyjątków z bloku catch(). Spowoduje to wywołanie funkcji terminate() i w konsekwencji zakończenie działania programu.

Informacje
Ostatnia modyfikacja 27-03-2009 10:29 Ostatni autor Mammoth
Ilość wyświetleń 1011 Wersja 4
Komentarz
winerfresh dnia 02-04-2009 18:19
Jeszcze nie ma, że w bloku catch(...) nie ma możliwości sprawdzenia co poleciało.
manfredek dnia 27-03-2009 15:45
Mammoth napisał:
I jeszcze te cytaty, za miesiąc ktoś napisze artykuł od nowa i wszystko w komentarzach będzie po prostu bez sensu :-).
O rly? O czymś takim jak 'Historia' słyszał?
Mammoth dnia 27-03-2009 10:33
najłatwiej to samemu nic nie robić, tylko komentować ;-) I jeszcze te cytaty, za miesiąc ktoś napisze artykuł od nowa i wszystko w komentarzach będzie po prostu bez sensu :-). Tego typu komenty można wysłać przez PW. Poza tym artykuł jest i tak lepszy niż poprzednia wersja.
manfredek dnia 25-03-2009 16:00
rzucanie wyjątków przez wartość zamiast przez referencję
Chyba łapanie?
Intelli dnia 25-03-2009 13:45
Jeżeli w artykule o wyjątkach ani razu nie pojawił się wyraz "stos", tzn. że taki tekst jest kompletnie bezwartościowy. A niniejszy artykuł zawiera jeszcze bardzo rażące błędy, jak na przykład "Wyjątek - jest to specjalny obiekt". I jeszcze to obrzydliwe rzucanie wyjątków przez wartość zamiast przez referencję - masakra. Nawet szkoda czasu na poprawianie. Całość do kosza.
manfredek dnia 23-03-2009 15:33
programik3 napisał:
2.Przestrzegaj kolejności sprawdzania wyjątków
WTF?
crayze dnia 23-03-2009 08:59
oj malutko, więc słabiutko

Katalog
Copyright © 2000-2006 by Coyote Group 0.9.3-pre3
Czas generowania strony: 0.0616 sek. (zapytań SQL: 9)