W moim interfejsie API mam małą hierarchię wyjątków, wyprowadzoną z std::exception
. Mam klasę podstawową Exception
, która zapewnia kod błędu, plik, linię i funkcję. Inne bardziej szczegółowe wyjątki pochodzą z Exception
. Na przykład jedna klasa pochodna dodaje specyficzny dla platformy kod błędu, a także pole identyfikujące, która funkcja zwróciła kod błędu. To jest jak uproszczona wersja system_error
, ale nie mogę używać funkcji C++ 11 (utknąłem przy pracy z VS2005 i bez Boost).Odłączanie wyjątków od formatowania logów
Muszę zalogować te wyjątki za pomocą mojej klasy logowania. Chcę, aby wyjątki były logowane w określonym formacie. Po przeczytaniu różnych forów online i przeczytaniu Boost's Error and Exception Handling Guidelines, nie sądzę, że funkcja what
każdego wyjątku lub jakiejkolwiek innej funkcji wirtualnej w obrębie Exception
jest odpowiednim miejscem do sformatowania wyjątku do rejestrowania. Dlatego moje funkcje what
po prostu zwracają nazwę klasy.
Podczas wychwytywania wyjątków często chcę wychwycić bardzo ogólne wyjątki, zwykle std::exception
, i przekazać je do rejestratora. Nie chcę wychwycić indywidualnych wyjątków bardzo często, ponieważ próbuję zapobiec wyjątkom przed wydostaniem się z interfejsu API (publiczna część mojego interfejsu API znajduje się w C) i może istnieć kilka wyjątków, które mogą wystąpić. Chcę uniknąć kod jak:
try { /* blah */ }
catch {DerivedException const& ex) { logger.log(ex); }
...
catch {Exception const& ex) { logger.log(ex); }
więc moim rejestrowania klasie, mój log
funkcja przyjmuje wartości std::exception
argumentem. Następnie używa typeid
, aby porównać parametr z różnymi klasami wyjątków, odlewając do odpowiedniego typu, a następnie wywołując funkcję logowania wyspecjalizowaną dla tego typu wyjątku. Jest to zasadniczo ta sama technika opisana jako in this other post.
używam typeid
zamiast dynamic_cast
ponieważ dynamic_cast
może odnieść sukces na każdej ważnej przygnębiony, a dla celów konserwacji kodu, ja naprawdę nie chcę kolejność moich if
sprawozdania w funkcji log
znaczenia.
Czy to jest przyzwoity projekt? Czuję się niesłusznie, używając mnie w ten sposób, ale myślę, że mam uzasadnione powody, aby to zrobić. Nie widziałem wiele wyjątków w obsłudze "na wolności", ponieważ pracujemy głównie z C, więc nie widziałem zbyt wielu podejść do tego tematu. Czy istnieją inne sposoby oddzielania wyjątków od ich formatowania logów, o których powinienem wiedzieć?
EDIT: Co ja zdecydowała się na wdrożenie
Wziąłem sugestię pomocą odwiedzający, ale dostosowany do mojego sytuacji. Chciałem złapać std::exception
, ponieważ można je wyrzucać tak samo jak moje, ale sformatować komunikat dziennika na podstawie typu wyjątku.
Każda z moich klas wyjątków wywodzi się z mojej podstawowej klasy Exception
i implementuje funkcję wirtualną accept
. Stworzyłem klasę ExceptionLogger
, która implementuje interfejs ExceptionVisitor
zapewniający funkcje visit
.
Klasa LogFile
ma instancję ExceptionLogger
, a także przeciążenie jej funkcji log
, która pobiera parametr std::exception
. W funkcji log
wypróbowuję dynamic_cast
dla mojego typu podstawowego, Exception
. Jeśli się powiedzie, zadzwonię do funkcji wyjątku, w innym wypadku zadzwonię bezpośrednio do funkcji ExceptionLogger::visit(std::exception const&)
.Ponieważ std::exception
nie implementuje mojej funkcji accept
, potrzebowałem dynamic_cast
, więc mogłem określić, czy możliwe jest bardziej szczegółowe rejestrowanie.
Wybrałem to zrobić zamiast serii if
sprawozdania sprawdzanie typeid
ponieważ:
- Jest to nazwane wzorzec projektowy, że mogę odnieść przyszłych opiekunów do
Jeżeli opiekun dodaje nowy wynikających wyjątku z mojej bazy
Exception
, ale zapomina o wprowadzeniu nowej funkcjivisit
dla tego wyjątku, nadal będę otrzymywać rejestrację, która została zaimplementowana dla bazyException
- pliku, numeru linii i funkcji.Gdybym wdrożył szereg
if
sprawozdania, bym musiał spaść z powrotem do zachowaniastd::exception
logowania, która jest po prostu wydrukować wyniki odwhat
lub może Próbowałemdynamic_cast
doException
.Oczywiście nadal wolałbym błąd kompilatora w tej sytuacji.
Alternatywą byłoby zastosowanie wzoru Odwiedzającego. –
@DDrmmr - Skończyło się na używaniu wzoru Visitor. Uczyń to jako odpowiedź i oznaczy to jako zaakceptowaną. –