Czytam o obsłudze wyjątków. Mam trochę informacji na temat obsługi wyjątków, ale mam kilka pytań:
- Kiedy zgłosić wyjątek?
- Czy zamiast zgłaszać wyjątek, możemy użyć wartości zwracanej do wskazania błędu?
- Jeśli chronię wszystkie moje funkcje blokami try-catch, czy nie zmniejszy to wydajności?
- Kiedy używać obsługi wyjątków?
- Widziałem projekt, w którym każda funkcja w tym projekcie zawierała blok try-catch (tj. Kod wewnątrz całej funkcji jest otoczony blokiem try-catch). Czy to dobra praktyka?
- Jaka jest różnica między try-catch i __try __except?
c++
windows
exception
exception-handling
Umesha MS
źródło
źródło
Odpowiedzi:
Oto dość obszerny przewodnik po wyjątkach, które moim zdaniem są obowiązkowe:
Wyjątki i obsługa błędów - C ++ FAQ lub C ++ FAQ lite
Zasadniczo należy zgłosić wyjątek, gdy program może zidentyfikować plik zewnętrznyproblem uniemożliwiający wykonanie. Jeśli otrzymasz dane z serwera, a te dane są nieprawidłowe, zgłoś wyjątek. Brak miejsca na dysku? Podaj wyjątek. Promienie kosmiczne uniemożliwiają przeszukiwanie bazy danych? Podaj wyjątek. Ale jeśli otrzymasz nieprawidłowe dane z własnego programu - nie zgłaszaj wyjątku. Jeśli twój problem pochodzi z twojego własnego złego kodu, lepiej jest użyć ASSERTów, aby się przed nim chronić. Obsługa wyjątków jest potrzebna do zidentyfikowania problemów, z którymi program nie może sobie poradzić, i poinformowania ich o użytkowniku, ponieważ użytkownik może sobie z nimi poradzić. Ale błędy w twoim programie nie są czymś, z czym użytkownik może sobie poradzić, więc awaria programu powie niewiele mniej niż „Wartość answer_to_life_and_universe_and_everything nie wynosi 42! To nigdy nie powinno się zdarzyć !!!! 11”.
Złap wyjątek, w którym możesz zrobić z nim coś użytecznego, na przykład wyświetlić okno komunikatu. Wolę złapać wyjątek w funkcji, która w jakiś sposób obsługuje dane wejściowe użytkownika. Na przykład, użytkownik naciska przycisk „Annihilate all hunams”, a wewnątrz funkcji annihilateAllHunamsClicked () znajduje się blok try ... catch, który mówi „Nie mogę”. Chociaż anihilacja hunamkinda jest złożoną operacją, która wymaga wywołania dziesiątek funkcji, jest tylko jedna próba ... złapanie, ponieważ dla użytkownika jest to operacja atomowa - jedno kliknięcie przycisku. Kontrole wyjątków w każdej funkcji są zbędne i brzydkie.
Nie mogę również polecić wystarczającego zaznajomienia się z RAII - to znaczy upewnienia się, że wszystkie zainicjowane dane są automatycznie niszczone. Można to osiągnąć, inicjując jak najwięcej na stosie, a kiedy chcesz zainicjować coś na stercie, użyj jakiegoś inteligentnego wskaźnika. Wszystko zainicjowane na stosie zostanie automatycznie zniszczone po wyrzuceniu wyjątku. Jeśli używasz głupich wskaźników w stylu C, ryzykujesz wyciek pamięci, gdy zostanie zgłoszony wyjątek, ponieważ nie ma nikogo, kto mógłby je wyczyścić po wyjątku (oczywiście, możesz użyć wskaźników w stylu C jako członków swojej klasy, ale upewnij się, że są zadbany w destructorze).
źródło
fclose
!). Nie da ci to pełnego śladu stosu.Wyjątki są przydatne w różnych okolicznościach.
Po pierwsze, istnieją pewne funkcje, w przypadku których koszt obliczenia warunku wstępnego jest tak wysoki, że lepiej jest po prostu wykonać obliczenia i przerwać z wyjątkiem, jeśli okaże się, że warunek wstępny nie jest spełniony. Na przykład nie można odwrócić macierzy osobliwej, jednak aby obliczyć, czy jest ona pojedyncza, należy obliczyć wyznacznik, który jest bardzo drogi: może i tak trzeba będzie to zrobić wewnątrz funkcji, więc po prostu „spróbuj” odwrócić macierz i podać raport błąd, jeśli nie możesz, zgłaszając wyjątek. Jest to w zasadzie wyjątek jako negatywne użycie warunku wstępnego .
Są też inne przypadki, w których kod jest już złożony i przekazywanie informacji o błędach w górę łańcucha wywołań jest trudne. Dzieje się tak częściowo dlatego, że C i C ++ mają zepsute modele struktury danych: są inne, lepsze sposoby, ale C ++ ich nie obsługuje (na przykład używanie monad w Haskell). To użycie jest w zasadzie nie przeszkadzało mi to zrobić dobrze, więc rzucę wyjątek : to nie jest właściwy sposób, ale jest praktyczny.
Następnie istnieje główne zastosowanie wyjątków: do zgłaszania, gdy zewnętrzne warunki wstępne lub niezmienniki, takie jak wystarczające zasoby, takie jak pamięć lub miejsce na dysku, nie są dostępne. W takim przypadku zazwyczaj kończysz program lub jego główną podsekcję, a wyjątkiem jest dobry sposób przekazywania informacji o problemie. Wyjątki C ++ zostały zaprojektowane do zgłaszania błędów, które uniemożliwiają kontynuowanie programu .
Model wyjątek obsługi używane w większości współczesnych języków, w tym C ++ jest znany być złamane. Jest o wiele za potężny. Teoretycy opracowali teraz lepsze modele niż całkowicie otwarty model „rzuć czymkolwiek” i „może, a może nie złap tego”. Ponadto używanie informacji o typie do klasyfikowania wyjątków nie było dobrym pomysłem.
Więc najlepszą rzeczą, jaką możesz zrobić, jest oszczędne rzucanie wyjątków, gdy występuje rzeczywisty błąd i nie ma innego sposobu, aby sobie z nim poradzić i wychwycić wyjątki jak najbliżej punktu rzutu .
źródło
Nie zgadzam się z tym aspektem przyjętej odpowiedzi . Asercja nie jest lepsza niż rzucenie wyjątku. Jeśli wyjątki były odpowiednie tylko w przypadku błędów czasu wykonywania (lub „problemów zewnętrznych”), po co
std::logic_error
?Błąd logiczny jest prawie z definicji rodzajem warunku, który uniemożliwia kontynuowanie programu. Jeśli program jest konstrukcją logiczną, a warunek występuje poza domeną tej logiki, jak można go kontynuować? Zbierzcie dane wejściowe, póki możecie, i rzućcie wyjątek!
To nie tak, że nie ma wcześniejszej sztuki.
std::vector
, żeby wymienić tylko jeden, zgłasza wyjątek błędu logicznego, a mianowiciestd::out_of_range
. Jeśli korzystasz z biblioteki standardowej i nie masz programu obsługi najwyższego poziomu do wychwytywania standardowych wyjątków - choćby po to, aby wywołać what () i wyjść (3) - wtedy twoje programy podlegają nagłemu cichemu zakończeniu.Makro asertujące jest znacznie słabszym strażnikiem. Nie ma powrotu do zdrowia. Chyba że nie uruchamiasz kompilacji debugowania, w którym to przypadku nie ma wykonania . Makro asertujące należy do epoki, w której obliczenia były o 6 rzędów wielkości wolniejsze niż obecnie. Jeśli masz kłopoty z testowaniem błędów logicznych, ale nie chcesz używać tego testu, gdy się liczy, w środowisku produkcyjnym, lepiej miej duże zaufanie do swojego kodu!
Biblioteka standardowa zapewnia wyjątki błędów logicznych i wykorzystuje je. Są tam z jakiegoś powodu: ponieważ występują błędy logiczne i są wyjątkowe. Tylko dlatego, że asercje funkcji C nie są powodem, aby polegać na takim prymitywnym (i prawdopodobnie bezużytecznym) mechanizmie, gdy wyjątek obsługuje zadanie o wiele lepiej.
źródło
Najlepiej do tego przeczytać
O obsłudze wyjątków mówi się wiele przez ostatnie półtorej dekady. Jednak pomimo ogólnego konsensusu co do tego, jak właściwie postępować z wyjątkami, nadal istnieje przepaść w stosowaniu. Niewłaściwa obsługa wyjątków jest łatwa do wykrycia, łatwa do uniknięcia i jest prostym miernikiem jakości kodu (i programisty). Wiem, że zasady absolutne wydają się być ograniczone lub przesadzone, ale generalnie nie powinieneś używać try / catch
http://codebetter.com/karlseguin/2010/01/25/don-t-use-try-catch/
źródło
try
/catch {}
?Sprawdzanie wyjątku jest zawarte w kodzie, gdy istnieje możliwość uzyskania wyjątku w wyniku lub gdzieś pomiędzy problemem.
2. Użyj bloku try-catch tylko w tych przypadkach, w których jest to wymagane. Użycie każdego bloku try-catch powoduje dodatkowe sprawdzenie warunków, które z pewnością ogranicza optymalizację kodu.
Myślę, że _try_except jest prawidłową nazwą zmiennej ...
źródło
Podstawowa różnica to:
jeden to ty robisz swoje.
Na przykład masz wyrażenie, które możesz zrobić
0 divide error
. Korzystanie z try catch1.
pomoże Ci w przypadku wystąpienia błędu. Lub potrzebujeszif a==0 then..
in2.
Jeśli nie spróbujesz złapać wyjątku, o którym nie sądzę, jest szybszy, jest to po prostu obejście, jeśli
error
wystąpi, zostanie skierowanythrew
do zewnętrznego modułu obsługi.Podejmowanie się oznacza, że problem nie idzie dalej, a w wielu przypadkach ma przewagę w szybkości, ale nie zawsze.
Sugestia: Po prostu radzisz sobie, kiedy jest to proste i logicznie uzasadnione.
źródło
Wielu purystów C / C ++ całkowicie odradza wyjątki. Główne zarzuty to:
Zamiast tego sprawdzaj zwracaną wartość / kod błędu za każdym razem, gdy wywołujesz funkcję.
źródło