Od czasu do czasu zauważam pewien wzór kodowania, który miałem od lat i denerwuje mnie to. Nie mam konkretnego problemu, ale nie pamiętam też wystarczająco, dlaczego przyjąłem ten wzorzec, a jakiś jego aspekt wydaje się pasować do jakiegoś wzorca. Niedawno zdarzyło mi się WRT, jak niektóre z mojego kodu używają wyjątków.Czy używam klauzuli catch C++, rodziny klas wyjątków i destrukcji?
Niepokojąca sprawa dotyczy przypadków, w których przechwyciłem wyjątek "przez odniesienie", traktując go w podobny sposób, w jaki sposób potraktowałem parametr funkcji. Jednym z powodów jest to, że mogę mieć hierarchię dziedziczenia klas wyjątków i określić bardziej ogólny lub bardziej precyzyjny typ catch, w zależności od aplikacji. Na przykład, mogę określić ...
class widget_error {};
class widget_error_all_wibbly : public widget_error {};
class widget_error_all_wobbly : public widget_error {};
void wibbly_widget()
{
throw widget_error_all_wibbly();
}
void wobbly_widget()
{
throw widget_error_all_wobbly();
}
void call_unknown_widget (void (*p_widget)())
{
try
{
p_widget();
}
catch (const widget_error &p_exception)
{
// Catches either widget_error_all_wibbly or
// widget_error_all_wobbly, or a plain widget_error if that
// is ever thrown by anything.
}
}
to teraz mnie niepokojące, ponieważ zauważyłem, że instancja klasy jest zbudowany (jako część rzutu) wewnątrz funkcji, ale jest wymieniony (przez p_Exception catch-clause "parameter") po wyjściu z tej funkcji. Zwykle jest to wzorzec zapobiegający - referencja lub wskaźnik do zmiennej lokalnej lub tymczasowej utworzonej w ramach funkcji, ale zanikający, gdy funkcja jest zakończona, jest zwykle zwisającym odnośnikiem/wskaźnikiem, ponieważ zmienna lokalna/tymczasowa jest niszczona, a pamięć zwalniana. po wyjściu funkcji.
Niektóre szybkie testy sugerują, że powyższy rzut jest prawdopodobnie poprawny - instancja skonstruowana w klauzuli throw nie zostanie zniszczona, gdy funkcja zostanie zakończona, ale zostanie zniszczona po zakończeniu catch-clause, która ją obsługuje - chyba że blok catch rzuci ponownie wyjątek, w którym to przypadku następny blok catch wykonuje to zadanie.
Moja pozostała nerwowość polega na tym, że test przeprowadzony w jednym lub dwóch kompilatorach nie jest dowodem na to, co mówi standard, a ponieważ moje doświadczenie mówi, że to, co uważam za zdrowy rozsądek, często różni się od tego, co gwarantuje język.
Czy ten wzór obsługi wyjątków (łapanie ich przy użyciu typu odniesienia) jest bezpieczny? Czy powinienem robić coś innego, takie jak ...
- Catching (i jawnie usuwanie) wskaźniki do wystąpień sterty przydzielone zamiast odniesienia do czegoś, co wygląda (gdy rzucony) bardzo podobny tymczasowy?
- Korzystanie z klasy inteligentnego wskaźnika?
- Korzystanie z klauzul catch catch-by-value i akceptacja, że nie mogę przechwycić żadnej klasy wyjątków z hierarchii z jedną klauzulą catch?
- Coś, o czym nie pomyślałem?
Również [używaj wirtualnego dziedziczenia] (http://www.boost.org/community/error_handling.html). – ybungalobill
@ybungalobill - Myślałem, że to żart, a potem przeczytałem link. Interesujący punkt. – Steve314