Niebezpieczne wyjątki
• tech • 285 słów • 2 minuty czytania
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ń.
Komentarze (0)