Kris Jamsa Wygraj Z C++ lekcja38


Lekcja 39LEKCJA 39
Obsługa błędów przy użyciu wyjątków języka C++
Po utworzeniu wielu programów i usunięciu z nich błędów możesz zacząć
przewidywać błędy wykonania, jakie mogą wystąpić podczas uruchamiania programu.
Na przykład, jeśli twój program czyta informacje z pliku, to powinien sprawdzać,
czy dany plik istnieje i czy program może go otworzyć. Analogicznie, jeśli
program przy użyciu operatora new przydziela pamięć, to powinien sprawdzać, czy
wystąpił brak pamięci i w odpowiedni sposób reagować. Gdy będziesz pisać duże i
złożone programy, to będziesz w nich umieszczać wiele takich testów. Podczas tej
lekcji dowiesz się, w jaki sposób możesz przy użyciu wyjątków języka C++
uprościć sprawdzanie w programach wystąpienia błędów i ich obsługę. Pod koniec
tej lekcji będziesz rozumiał następujące zagadnienia podstawowe:
Wyjątek to nieoczekiwane zdarzenie, błąd w programie.
W programach definiujesz wyjątki jako klasy.
Aby nakazać programowi szukanie wyjątków, należy użyć instrukcji try.
Do wykrywania konkretnego wyjątku służy instrukcja catch.
Aby po wystąpieniu błędu generować wyjątek, należy używać instrukcji throw.
Gdy program wykryje (przechwyci) wyjątek, to wywołuje specjalną dla tego
wyjątku funkcję obsługi wyjątku.
Niektóre starsze kompilatory języka C++ nie akceptują wyjątków.


C++ reprezentuje wyjątki jako klasy
Twoim celem używania wyjątków języka C++ jest uproszczenie wykrywania i błędów i
reagowania na nie w programie. W sytuacji idealnej, gdy podczas wykonywania
programu wystąpi nieoczekiwany błąd (wyjątek), program powinien nie tylko
zakończyć swoje działanie, ale... W programie definiujesz każdy wyjątek jako
klasę. Na przykład, następujące instrukcje definiują trzy wyjątki związane z
operacjami na plikach:
class blad_otwarcia_pliku {};
class blad_czytania_pliku {};
class blad_pisania_pliku {};



Instruowanie C++, by sprawdzał, czy wystąpił wyjątek
Zanim program będzie mógł wykrywać wyjątki i reagować na nie musisz przy użyciu
instrukcji try języka C++ włączyć wykrywanie wyjątków. Na przykład. następująca
instrukcja try włącza wykrywanie wyjątków dla wywołania funkcji kopiuj_plik:
try {
kopiuj_plik ("ZRODLO.TXT", "CEL.TXT");
};

Bezpośrednio za instrukcją try program powinien zawierać jedną lub więcej
instrukcji catch języka C++. który z wyjątków miał miejsce:
try {
kopiuj_plik ("ZRODLO.TXT", "CEL.TXT");
};

catch (blad_otwarcia_pliku) {
cerr << "Błąd podczas próby otwarcia pliku źródłowego lub docelowego"
<< endl;
exit (1);
}

catch (blad_czytania_pliku) {
cerr << "Błąd podczas próby czytania na pliku źródłowym" << endl;
exit (1);
}

catch (blad_pisania_pliku) {
cerr << "Błąd podczas próby pisania w pliku docelowym" << endl;
exit (1);
}

Jak widzimy, przedstawiony kod sprawdza. czy miał miejsce któryś ze
zdefiniowanych wyjątków operacji na pliku. W tym przykładzie. niezależnie od
rodzaju błędu, wyświetlany jest odpowiedni komunikat i wykonywanie programu
zostaje zakończone. W sytuacji idealnej program mógłby reagować w inny sposób.
być może próbując wyeliminować przyczynę błędu i ponawiając próbę wykonania
operacji. Jeśli funkcja działa poprawnie i nie generuje wyjątku, C++ po prostu
pomija instrukcje catch.


Generowanie wyjątków przy użyciu instrukcji throw
Sam C++ nie generuje wyjątków. Robi to program przy użyciu instrukcji throw. Na
przykład, w funkcji kopiuj_plik można sprawdzać, czy wystąpił błąd i generować
wyjątek w następujący sposób:
void kopiuj_plik (char *zrodlo, char *cel)
{
char linie[256];

ifstream plik_wejsc(zrodlo);
ofstream plik_wyjsc(cel);

if (plik_wejsc.fail())
hrow(blad_otwarcia_pliku);
else if (plik_wejsc.fail())
hrow(blad_otwarcia_pliku);
else
{
while ((! plik_wejsc.eof()) && (! plik_wejsc.fail()))
{
plik_wejsc.getline (linia, sizeof(linia));

if (! plik_wejsc.fail())
plik_wyjsc << linia << endl;
else
throw (blad_czytania_pliku);
if ( plik_wyjsc.fail())
throw (blad_pisania_pliku);
}
}
}

Jak widzimy, program przy użyciu instrukcji throw generuje wyjątki.
Na czym polegają wyjątki
Przy użyciu wyjątków programy mogą sprawdzić, czy wystąpił błąd i jeśli tak to
generować wyjątek przy użyciu instrukcji throw. W odpowiedzi na to C++ uaktywni
funkcję obsługi wyjątku (jej instrukcje definiujesz w klasie wyjątku). Po
zakończeniu funkcji obsługi wyjątku C++ zwraca sterowanie do pierwszej
instrukcji po instrukcji try, która uaktywniła wykrywanie wyjątku. Następnie
program może za pomocą instrukcji catch określić, jaki wyjątek miał miejsce i
podjąć odpowiednie działania.


Definiowanie obsługi wyjątków
Gdy program wyrzuca wyjątek, C++ uruchamia obsługę wyjątku (funkcję), której
instrukcje definiowane są wewnątrz klasy wyjątku. Na przykład, następująca klasa
wyjątku alarm_nukl definiuje instrukcje obsługi wyjątku w funkcji alarm_nukl:
class alarm_nukl {
public:
alarm_nukl (void) {cerr << "\a\a\a Uciekaj!" << endl;}
};

W tym przykładzie, gdy program znajdzie wyjątek alarm_nukl, C++ wykona
instrukcje funkcji alarm_nukl, a potem sterowanie wróci do pierwszej instrukcji
za instrukcją try, która włączyła wykrywanie wyjątków. Przedstawiony poniżej
program NUKL.CPP ilustruje sposób korzystania z funkcji alarm_nukl. Przy użyciu
instrukcji try jest włączane wykrywanie wyjątków. Następnie program wywołuje
funkcję dodaj_u232 z parametrem ilosc. Jeśli wartość parametru jest mniejsza od
255, to funkcja zostanie wykonana poprawnie. Jeśli natomiast wartość parametru
jest równa co najmniej 255, to funkcja uruchomi obsługę wyjątku alarm_nukl:
#include

class alarm_nukl {
public:
alarm_nukl (void) {cerr << "\a\a\a W nogi!" << endl;}
};

void dodaj_u232 (int ilosc)
{
if (ilosc < 255)
cout << "Ilość u232 jest bezpieczna" << endl;
else
throw alarm_nukl();
}

void main(void)
{
try {
dodaj_u232(255);
}

catch (alarm_nukl) {
cerr << "Szybciej!" << endl;
}
}

Gdy skompilujesz i uruchomisz ten program, to otrzymasz na ekranie następujące
wyjście:
C:\> NUKL
W nogi!
Szybciej!

Jeśli przeanalizujesz w kodzie źródłowym instrukcje wypisujące komunikaty, to
zobaczysz, w jaki sposób wyjątek jest obsługiwany zarówno przez funkcję obsługi,
jak i przez instrukcję catch. Pierwszy komunikat jest wypisywany przez funkcję
alarm_nukl, a drugi przez instrukcję catch wykrywającą wyjątek.
Definiowanie funkcji obsługi wyjątków
Gdy C++ wykryje w programie wyjątek, to wywołuje specjalną funkcję obsługi
wyjątków. Aby zdefiniować taką funkcję, należy utworzyć w klasie wyjątku funkcję
o tej samej nazwie co wyjątek (analogicznie jak dla konstruktora). Gdy program
podczas wykonywania się napotka wyjątek, to C++ automatycznie wywoła odpowiednią
funkcję obsługi. W idealnej sytuacji funkcja obsługi wyjątku powinna realizować
operacje, które naprawiają błąd, tak aby program mógł ponowić próbę działania,
które spowodowało pojawienie się wyjątku. Po zakończeniu wykonywania funkcji
obsługi wyjątku program przechodzi do pierwszej instrukcji za instrukcją try,
która włączyła wykrywanie wyjątków.


Zmienne składowe wyjątku
W przedstawionych przykładach programy przy użyciu instrukcji catch mogły
określić, który wyjątek miał miejsce i w odpowiedni sposób na niego zareagować.
W idealnym przypadku, im więcej informacji na temat wyjątku ma program, tym
lepiej może na niego zareagować. Na przykład, dla wyjątku blad_otwarcia_pliku
program powinien znać nazwę pliku. Analogicznie w przypadku wyjątków
blad_czytania_pliku i blad_pisania_pliku program powinien znać miejsce
wystąpienia błędu. Aby przechowywać takie informacje o wyjątku, należy po prostu
dodać do klasy wyjątku odpowiednie zmienne składowe. Gdy program podczas
wykonywania się napotka wyjątek, to przekaże odpowiednią informację jego funkcji
obsługi jako parametr:
throw blad_otwarcia_pliku(plik_wejsc);
throw blad_czytania_pliku(344);

W funkcji obsługi wyjątku są instrukcje przypisujące parametrom odpowiednie
zmienne składowe (analogicznie jak dla konstruktora). Na przykład, przedstawione
poniżej instrukcje tak modyfikują wyjątek blad_otwarcia_pliku, żeby przypisywać
nazwę pliku odpowiedniej zmiennej składowej:
class blad_otwarcia_pliku {
public:
blad_otwarcia_pliku (char *nazwapliku) {
strcpy (blad_otwarcia_pliku::nazwapliku, nazwapliku);};
char nazwapliku[255];
};



Obsługa nieprzewidzianych wyjątków
Wiesz już, że kompilatory C++ dają Ci do dyspozycji bibliotekę run-time funkcji,
które możesz wykorzystywać w swoich programach. Czytając ich dokumentację możesz
napotkać funkcje, które przechwytują konkretne wyjątki. W takich przypadkach
programy powinny sprawdzać, czy ma miejsce odpowiedni wyjątek. Standardowo,
jeśli program napotka wyjątek, dla którego nie zdefiniowałeś funkcji obsługi, to
wywołana zostanie standardowa funkcja obsługi z C++. W większości sytuacji
standardowa funkcja obsługi wyjątku kończy działanie programu. Przedstawiony
poniżej program NIEZAP.CPP ilustruje, w jaki sposób standardowa funkcja obsługi
wyjątku kończy wykonywanie programu.
#include

class wyjatek {};

void main(void)
{
cout << "Przed przechwyceniem wyjątku" << endl;
throw wyjatek();
cout << "Wykrytu wyjątek" << endl;
}

W tym przypadku, gdy program wykryje wyjątek (który nie jest przez mego
obsługiwany), to C++ wywoła standardową funkcję obsługi wyjątków, która zakończy
wykonywanie programu. Zatem ostatnia instrukcja programu, która powinna
wyświetlić komunikat o wykryciu wyjątku, nie jest nigdy wykonywana. Zamiast
korzystać ze standardowej funkcji obsługi wyjątku języka C++, możesz w swoich
programach definiować własne standardowe funkcje obsługi. Aby poinformować C++ o
standardowej funkcji obsługi programu, należy wywołać funkcję biblioteczną
set_unexpected. Jej prototyp jest zdefiniowany w pliku nagłówkowym except.h.


Ustalanie, które wyjątki funkcja ma przechwytywać
Jak już mówiliśmy, prototyp funkcji pozwala definiować typy parametrów i typ
wartości funkcji. Przy użyciu prototypu funkcji można również określać, jakie
wyjątki funkcja ma przechwytywać. Na przykład, poniższy prototyp funkcji
informuje kompilator C++, że funkcja wlacz_reaktor ma przechwytywać wyjątki
alarm_nukl i napromieniowanie:
void wlacz_reaktor (long moc) throw (alarm_nukl, napromieniowanie);

Dzięki umieszczaniu w ten sposób w prototypie funkcji możliwych wyjątków inni
programiści czytający kod programu będą wiedzieli, jakie wyjątki trzeba
sprawdzać przy wykorzystywaniu funkcji.


Wyjątki i klasy
Przy tworzeniu klas może się zdarzyć, że będziesz chciał zdefiniować wyjątki
specyficzne dla danej klasy. Aby utworzyć wyjątek specyficzny dla klasy, należy
zdefiniować go jako jedną z publicznych składowych tej klasy. Na przykład,
poniższa klasa tekst definiuje dwa wyjątki:
class tekst {
public:
tekst (char *txt);
void wypelnij (*txt);
void pisz (void);
int dlugosc (void);
class pusty_tekst { };
class nadmiar_tekst { };
private:
int dlug;
char tekst[255];
};

Jak widzimy, w klasie są zdefiniowane wyjątki pusty_tekst i nadmiar_tekst. W
programie możesz sprawdzać wyjątki przy użyciu operatora widoczności i nazwy
klasy, np.:
try {
pweien_tekst.wypelnij (dlugi_tekst);
};

catch (tekst::nadmair_tekst) {
cerr << "Za długi tekst" << endl;
}



Zapamiętaj
Wyjątki mają za zadanie uprościć i ulepszyć wykrywanie błędów w programach i
reagowanie na nie. Do sprawdzania i wykrywania wyjątków służą instrukcje try,
catch i throw. Znajomość wyjątków dopełnia twoją wiedzę o programowaniu w C++.
Zanim będziesz kontynuować pracę z C++ upewnij się, że dobrze rozumiesz
następujące zagadnienia podstawowe:
Wyjątek to nieoczekiwany błąd podczas wykonywania programu.
Programy powinny wykrywać wyjątki i reagować na nie (obsługiwać je).
Definiujesz każdy wyjątek w programie jako klasę.
Aby nakazać kompilatorowi C++ wykrywanie wyjątku, należy użyć instrukcji try.
Bezpośrednio za instrukcją try powinieneś umieszczać instrukcję catch, aby
ustalićjaki wyjątek miał miejsce.
C++ sam nie generuje wyjątków. Natomiast programy generują wyjątki przy użyciu
instrukcji throw.
W prototypie funkcji możesz określić, jakie wyjątki ma ona przechwytywać.
Czytając dokumentację biblioteki run-time, pamiętaj, że pewne funkcje mogą
generować wyjątki.
Jeśli program przechwyci nie obsługiwany wyjątek, to wywoła dla niego
standardową funkcję obsługi.
Plik nagłówkowy except.h określa prototypy funkcji, które możesz wykorzystywać
w programach do definiowania standardowego zakończenia i funkcji dla nie
obsługiwanych wyjątków.



WsteczSpis treści



Wyszukiwarka

Podobne podstrony:
Kris Jamsa Wygraj Z C lekcja32
Kris Jamsa Wygraj Z C lekcja 5
Kris Jamsa Wygraj Z C lekcja23
Kris Jamsa Wygraj Z C lekcja35
Kris Jamsa Wygraj Z C lekcja20
Kris Jamsa Wygraj Z C lekcja27
Kris Jamsa Wygraj Z C lekcja34
Kris Jamsa Wygraj Z C lekcja18
Kris Jamsa Wygraj Z C lekcja17
Kris Jamsa Wygraj Z C lekcja25
Kris Jamsa Wygraj Z C lekcja14
Kris Jamsa Wygraj Z C lekcja36
Kris Jamsa Wygraj Z C lekcja 4
Kris Jamsa Wygraj Z C lekcja33
Kris Jamsa Wygraj Z C lekcja 7
Kris Jamsa Wygraj Z C lekcja30
Kris Jamsa Wygraj Z C lekcja12
Kris Jamsa Wygraj Z C lekcja28
Kris Jamsa Wygraj Z C lekcja 6

więcej podobnych podstron