W C ++ można określić, że funkcja może, ale nie musi, zgłaszać wyjątek przy użyciu specyfikatora wyjątku. Na przykład:
void foo() throw(); // guaranteed not to throw an exception
void bar() throw(int); // may throw an exception of type int
void baz() throw(...); // may throw an exception of some unspecified type
Wątpię, czy faktycznie ich używam z następujących powodów:
- Kompilator tak naprawdę nie narzuca specyfikatorów wyjątków w żaden rygorystyczny sposób, więc korzyści nie są duże. Idealnie byłoby, gdybyś chciał otrzymać błąd kompilacji.
- Jeśli funkcja narusza specyfikator wyjątku, myślę, że standardowym zachowaniem jest zakończenie programu.
- W VS.Net traktuje rzut (X) jako rzut (...), więc trzymanie się standardu nie jest mocne.
Czy uważasz, że należy używać specyfikatorów wyjątków?
Odpowiedz „tak” lub „nie” i podaj powody uzasadniające odpowiedź.
Odpowiedzi:
Nie.
Oto kilka przykładów, dlaczego:
Nie można zapisać kodu szablonu ze specyfikacjami wyjątków,
Kopie mogą zostać rzucone, przekazanie parametru może zgłosić i
x()
może zgłosić nieznany wyjątek.Specyfikacje wyjątków zwykle zabraniają rozszerzalności.
może ewoluować w
Naprawdę możesz to napisać jako
Pierwsza nie jest rozszerzalna, druga jest zbyt ambitna, a trzecia jest naprawdę tym, co masz na myśli, pisząc funkcje wirtualne.
Starszy kod
Kiedy piszesz kod, który opiera się na innej bibliotece, tak naprawdę nie wiesz, co może zrobić, gdy coś pójdzie nie tak.
g
kończy się, gdylib_f()
rzuca. To (w większości przypadków) nie jest to, czego naprawdę chcesz.std::terminate()
nigdy nie należy nazywać. Zawsze lepiej jest pozwolić aplikacji zawiesić się z nieobsługiwanym wyjątkiem, z którego można pobrać ślad stosu, niż cicho / gwałtownie umrzeć.Napisz kod, który zwraca typowe błędy i wyrzuca w wyjątkowych sytuacjach.
Niemniej jednak, gdy Twoja biblioteka po prostu zgłasza własne wyjątki, możesz użyć specyfikacji wyjątków, aby określić swój zamiar.
źródło
try {...} catch (<specified exceptions>) { <do whatever> } catch (...) { unexpected(); ]
konstrukcję, niezależnie od tego, czy chcesz tam blokować try.try { <<...code...>> } catch(...) /* stack guaranteed to be unwound here and dtors run */ { throw; /* pass it on to the runtime */ }
terminate()
? Dlaczego po prostu nie zadzwoniszabort()
?Unikaj specyfikacji wyjątków w C ++. Powody, które podajesz w swoim pytaniu, to całkiem dobry początek.
Zobacz „Pragmatic Look at Exception Specifications” Herba Suttera .
źródło
throw(optional-type-id-list)
) jest przestarzałe w C ++ 11. Nadal są w standardzie, ale wydaje mi się, że wysłano ostrzeżenie, że należy dokładnie rozważyć ich użycie. C ++ 11 dodajenoexcept
specyfikację i operator. Nie znam wystarczająco dużo szczegółów,noexcept
aby to skomentować. Ten artykuł wydaje się być dość szczegółowy: akrzemi1.wordpress.com/2011/06/10/using-noexcept A Dietmar Kühl opublikował artykuł w Overload Journal z czerwca 2011 r .: accu.org/var/uploads/journals/overload103.pdfthrow(something)
jest uważany za bezużyteczny i zły pomysł.throw()
jest przydatny.Wydaje mi się, że standardowo poza konwencją (dla C ++)
specyfikatory wyjątków były eksperymentem w standardzie C ++, który w większości się nie powiódł.
Wyjątkiem jest to, że specyfikator no throw jest przydatny, ale należy również wewnętrznie dodać odpowiedni blok try catch, aby upewnić się, że kod pasuje do specyfikatora. Herb Sutter ma stronę na ten temat. Gniew 82
Dodatkowo myślę, że warto opisać Gwarancje Wyjątków.
Są to w zasadzie dokumentacja opisująca, w jaki sposób na stan obiektu wpływają wyjątki uciekające przed metodą na tym obiekcie. Niestety, kompilator nie wymusza ich ani nie wspomina o nich w inny sposób.
Wzmocnienie i wyjątki
Gwarancje wyjątków
Bez gwarancji:
Gwarancja podstawowa:
Silna gwarancja: (inaczej gwarancja transakcyjna)
Gwarancja braku rzutu:
źródło
Guarantee that functions will only throw listed exceptions (possibly none)
. Nie prawda. Gwarantuje tylko, że jeśli funkcja zgłosi te wyjątki, aplikacja zakończy działanie.Enable compiler optimizations based on the knowledge that only listed exceptions (possibly none) will be thrown
Nie mogę tego zrobić. Ponieważ właśnie wskazałem, nie możesz zagwarantować, że wyjątek nie zostanie zgłoszony.throw()
(nie zgłasza). " Gwarantuje tylko, że jeśli funkcja zgłosi te wyjątki, aplikacja zakończy działanie. „ Nie ”nie prawda” oznacza prawdę. W C ++ nie ma gwarancji, że funkcjaterminate()
nigdy nie wywoła. „ Ponieważ właśnie wskazałem, nie możesz zagwarantować, że wyjątek nie zostanie zgłoszony ” Gwarantujesz, że funkcja nie zgłosi. Właśnie tego potrzebujesz.gcc będzie emitować ostrzeżenia, gdy naruszysz specyfikacje wyjątków. To, co robię, to używać makr do używania specyfikacji wyjątków tylko w trybie "lint", kompilując się wyraźnie w celu sprawdzenia, czy wyjątki są zgodne z moją dokumentacją.
źródło
Jedynym użytecznym specyfikatorem wyjątku jest „throw ()”, na przykład „nie rzuca”.
źródło
Specyfikacje wyjątków nie są cudownie użytecznymi narzędziami w C ++. Jednak jest / jest / dobry dla nich użytek, jeśli połączymy je z std :: nieoczekiwany.
To, co robię w niektórych projektach, to kod ze specyfikacjami wyjątków, a następnie wywołanie metody set_uknown () z funkcją, która wyrzuci specjalny wyjątek mojego własnego projektu. Ten wyjątek, po skonstruowaniu, pobiera ślad wsteczny (w sposób specyficzny dla platformy) i pochodzi z std :: bad_exception (aby umożliwić propagację w razie potrzeby). Jeśli wywołuje wywołanie terminate (), jak to zwykle bywa, ślad wstecz jest wypisywany przez what () (jak również oryginalny wyjątek, który go spowodował; nie jest to trudne do znalezienia), więc otrzymuję informacje o tym, gdzie znajdował się mój kontrakt naruszony, na przykład zgłoszony nieoczekiwany wyjątek biblioteki.
Jeśli to zrobię, nigdy nie zezwalam na propagację wyjątków bibliotek (z wyjątkiem tych std) i wyprowadzam wszystkie moje wyjątki z std :: wyjątek. Jeśli biblioteka zdecyduje się rzucić, złapię i przekonwertuję na swoją własną hierarchię, pozwalając mi zawsze kontrolować kod. Funkcje oparte na szablonach, które wywołują funkcje zależne, powinny unikać specyfikacji wyjątków z oczywistych powodów; ale i tak rzadko zdarza się mieć interfejs funkcji oparty na szablonach z kodem biblioteki (a kilka bibliotek naprawdę używa szablonów w użyteczny sposób).
źródło
Jeśli piszesz kod, który będzie używany przez ludzi, którzy woleliby przyjrzeć się deklaracji funkcji niż jakimkolwiek komentarzom wokół niej, wówczas specyfikacja powie im, które wyjątki mogą chcieć przechwycić.
W przeciwnym razie nie uważam za szczególnie przydatne używanie czegokolwiek poza
throw()
wskazaniem, że nie zgłasza żadnych wyjątków.źródło
Nie. Jeśli ich użyjesz i zostanie wyrzucony wyjątek, którego nie określiłeś, ani przez swój kod, ani przez kod wywoływany przez Twój kod, wtedy domyślnym zachowaniem jest natychmiastowe zakończenie programu.
Uważam również, że ich użycie zostało uznane za przestarzałe w aktualnych wersjach standardu C ++ 0x.
źródło
Specyfikacja „throw ()” umożliwia kompilatorowi wykonanie pewnych optymalizacji podczas wykonywania analizy przepływu kodu, jeśli wie, że funkcja nigdy nie zgłosi wyjątku (lub przynajmniej obiecuje, że nigdy nie zgłosi wyjątku). Larry Osterman mówi o tym krótko tutaj:
http://blogs.msdn.com/larryosterman/archive/2006/03/22/558390.aspx
źródło
Generalnie nie użyłbym specyfikatorów wyjątków. Jednak w przypadkach, gdy jakikolwiek inny wyjątek miałby pochodzić od danej funkcji, program ostatecznie nie byłby w stanie skorygować , może być przydatny. We wszystkich przypadkach upewnij się, że jasno udokumentowałeś, jakich wyjątków można oczekiwać od tej funkcji.
Tak, oczekiwanym zachowaniem niewyszczególnionego wyjątku generowanego przez funkcję ze specyfikatorami wyjątków jest wywołanie terminate ().
Zwrócę również uwagę, że Scott Meyers porusza ten temat w bardziej efektywnym języku C ++. Jego efektywne C ++ i bardziej efektywne C ++ są wysoce polecanymi książkami.
źródło
Tak, jeśli interesujesz się wewnętrzną dokumentacją. A może napisanie biblioteki, z której będą korzystać inni, aby mogli powiedzieć, co się stanie, bez zapoznania się z dokumentacją. Rzucanie lub nie wyrzucanie można uznać za część interfejsu API, prawie jak wartość zwracana.
Zgadzam się, nie są one tak naprawdę przydatne do wymuszania poprawności stylu Java w kompilatorze, ale jest lepsze niż nic lub przypadkowe komentarze.
źródło
Mogą być przydatne do testowania jednostkowego, aby podczas pisania testów wiedzieć, czego oczekiwać, że funkcja wyrzuci, gdy się nie powiedzie, ale nie ma ich wymuszania w kompilatorze. Myślę, że to dodatkowy kod, który nie jest potrzebny w C ++. Zawsze wybierasz wszystko, czego powinieneś być pewien, to przestrzeganie tego samego standardu kodowania w całym projekcie i członkach zespołu, dzięki czemu kod pozostaje czytelny.
źródło
Z artykułu:
http://www.boost.org/community/exception_safety.html
I rzeczywiście, mogę wymyślić sposoby uczynienia wyjątków klas szablonów bezpiecznymi. Jeśli nie masz kontroli nad wszystkimi podklasami, i tak możesz mieć problem. Aby to zrobić, można utworzyć w klasach typedefs, które definiują wyjątki wyrzucane przez różne klasy szablonów. Uważam, że problem polega na tym, że jak zwykle rozwiążemy to później, w przeciwieństwie do projektowania od samego początku, i myślę, że to ten koszt jest prawdziwą przeszkodą.
źródło
Specyfikacje wyjątków = bzdury, zapytaj dowolnego programistę Java w wieku powyżej 30 lat
źródło