Niebezpieczne wyjątki

20 października 2008

Ostatnio trochę marudziłem o rzucaniu wyjątków w konstruktorach, to dziś może wspomnę o destruktorach i konstruktorach kopiujących.

Każdy chyba wie, że nie należy rzucać wyjątków z destruktorów. To samo dotyczy konstruktora kopiującego obiektu wyjątku.

Problem z destruktorami jest to związany z obsługą wyjątku przez kompilator (czas miedzy rzuceniem wyjątku a złapaniem go przez odpowiedni catch), czyli rozwijaniem stosu przez kompilator i wywoływaniu destruktorów dla zmiennych lokalnych znajdujących się w zasięgu, którym zgłoszono sytuacje wyjątkową.

Czyli jak łatwo się domyślić, nie jest zalecane rzucenie wyjątku w destruktorze wykonywanym w czasie obsługi wyjątku przez kompilator, bo doprowadzi do katastrofy – w ogólnym przypadku program wywoła std::terminate().

Istnieje funkcja std::uncaught_exception(), która zwraca true, jeśli akurat znajdujemy się w trakcie obsługiwania wyjątku. Dzięki niej możemy się dowiedzieć czy np. destruktor został wywołany normalnie, czy z powodu wystąpienia sytuacji wyjątkowej.

Aczkolwiek nie jest to zbytnio zalecane. Trochę wiecej informacji na ten temat można znaleźć w GotW #47.

Odnośnie konstruktorów kopiujących obiektu wyjątku, problem związany jest z możliwością skopiowania „rzuconego” obiektu w czasie jego obsługi przez kompilator. Gdy w tym czasie copy ctor obiektu wyjątku zgłosiłby kolejny wyjątek, sprawa wyglądałaby tak jak w przypadku wyjątków w destruktorach – rzucony wyjątek w czasie obsługi innego wyjątku – terminate().

Dlatego nie należy traktować dowolnej klasy jako obiektu wyjątku. Należy odpowiednio zadbać o zabezpieczenia klas, których zastosowanie przewidujemy do wyjątków. Klasa, która rzuca
wyjątkami w konstruktorach, a tym szczególnie w kopiującym, w ogóle nie nadaje się do wyjątków.

Jako przykład weźmy std::exception.

Dlaczego w implementacji standardowych klas wyjątków zastosowano char* zamiast std::string?

Ponieważ konstruktor kopiujący std::string może rzucić wyjątkiem std::bad_alloc. Dlatego unika się w implementacjach klas wyjątków wykorzystywanie dynamicznych struktur, choć często o tym niewielu pamięta i pomijana jest tak kwestia w większości zastosowań.

Podobne notatki:

Może zainteresują Cię również następujące, pododbne notatki:

Nikt jeszcze nie skomentował tego wpisu.
Możesz być pierwszy.

Dodaj swój komentarz

Możesz użyć tych tagów XHTML-a: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Jeśli chcesz wstawić kilku linijkowy fragment kodu, użyj tagów <pre lang="x"></pre> (gdzie x język kodu np. cpp, perl, html). W ten sposób kod zostanie odpowiednio sformatowany i pokolorowany przez system.

Uwaga!

Na tym blogu działa system cache oraz filtr antyspamowy. Twój komentarz może być widoczny na stronie z pewnym opóźnieniem. Proszę o cierpliwość. Jeśli utraciłeś już wszystkie jej zasoby poinformuj mnie o tym, być może system uznał Cię za spamera ;)