Obsługa wyjątków
Wyjątek - jest to specjalny obiekt zgłaszany przez program, powodujący przerwanie wykonywania danej części kodu
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:
Do zgłaszania wyjątków służy słowo kluczowe throw
Warto wiedzieć, że nie musimy w ten sposób rzucać obiektów klas. Równie dobrze możemy posłużyć się typem wbudowanym:
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):
Przykładowy kod przyjmijmy taki:
W takim wypadku, jeżeli zgłosimy Karambol
wyjątek ten zostanie przechwycony przez blok:
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:
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:
Na takiej samej zasadzie, jeżeli usuniemy blok odpowiedzialny za łapanie Karambolu, łapać takie wyjątki będzie blok:
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:
wyjątek ten zostanie przechwycony przez ostatni blok catch.
Kolejność łapania wyjątków nie jest dowolna. Następujący kod:
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.
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
}
{
// 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:
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:
- 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:
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";
}
{
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:
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:
Na takiej samej zasadzie, jeżeli usuniemy blok odpowiedzialny za łapanie Karambolu, łapać takie wyjątki będzie blok:
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:
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.
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.
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


