Ostatnio staram się zrozumieć, jaka jest właściwa ilość sprawdzania i jakie są właściwe metody.
Mam kilka pytań na ten temat:
Jaki jest właściwy sposób sprawdzania błędów (złe dane wejściowe, złe stany itp.)? Czy lepiej jest jawnie sprawdzać błędy, czy używać funkcji takich jak asercje, które można zoptymalizować z końcowego kodu? Mam wrażenie, że jawnie sprawdzam bałagan w programie z dużą ilością dodatkowego kodu, który i tak nie powinien być wykonywany w większości sytuacji - i nie wspominając o tym, że większość błędów kończy się niepowodzeniem przerwania / wyjścia. Po co zaśmiecać funkcję wyraźnymi kontrolami, aby po prostu przerwać? Szukałem stwierdzeń w porównaniu do jawnego sprawdzania błędów i nie znalazłem niewiele, aby naprawdę wyjaśnić, kiedy to zrobić.
Większość mówi „użyj twierdzeń, aby sprawdzić błędy logiczne, i użyj jawnych kontroli, aby sprawdzić inne błędy”. Wydaje się, że to nie prowadzi nas tak daleko. Czy moglibyśmy powiedzieć, że jest to wykonalne:
Malloc returning null, check explictly
API user inserting odd input for functions, use asserts
Czy to poprawiłoby mnie w sprawdzaniu błędów? Co jeszcze mogę zrobić? Naprawdę chcę poprawić i napisać lepszy, „profesjonalny” kod.
źródło
setjmp
/longjmp
są dostępne w C, więc nie potrzebujesz nowego języka.Odpowiedzi:
Najłatwiejszym sposobem, aby stwierdzić różnicę, jest ustalenie, czy warunek błędu zostanie wprowadzony w czasie kompilacji, czy w czasie wykonywania. Jeśli problem polega na tym, że programista w jakiś sposób źle używa tej funkcji, spraw, aby zwrócenie uwagi na problem, ale gdy poprawka zostanie wkompilowana w kod wywołujący, nie musisz się już martwić o jej sprawdzenie. W czasie kompilacji nie można rozwiązać problemów, takich jak brak pamięci lub złe dane wejściowe użytkownika końcowego, więc pozostaw kontrolę.
źródło
Sprawdź wszystko w dowolnym momencie (mogło się to zmienić po ostatniej kontroli), co nie jest w 100% pod twoim dowództwem. A także: Podczas rozwoju nawet nie ufaj sobie! ;-)
Okokok ... „cokolwiek” należy rozumieć jako sprawdzanie takich rzeczy, które spowodowałyby nienormalne przerwanie lub cokolwiek, co mogłoby zmusić twoją aplikację / system do robienia rzeczy, których nie powinno robić.
Mówiąc poważnie, ostatnia część ostatniego zdania jest niezbędna, ponieważ wskazuje na główny problem:
Jeśli chcesz zbudować stabilny system główny problem to nie o tym, co system powinien robić, ale niech to będzie w stanie zrobić takich obowiązkowych rzeczy, trzeba zadbać o to, co powinno nie robić, nawet jeśli jest „zaśmiecanie kod".
źródło
Istotą obsługi błędów nie jest to, czy i jak złapiesz problem. To więcej, co robisz po tym, jak się o tym dowiesz .
Po pierwsze - powiedziałbym, że nie ma powodu, dla którego zwracany byłby pojedynczy błąd zwracany metodą podrzędną. Błędy i wyjątki to coś więcej niż zwracane wartości lub wszystkie try / catch.
Sam rzut i łapanie nie wystarczy.
Zobacz : gdzie autor wyjaśnia, że po prostu wyłapując, ale nie robiąc nic, potencjalnie nie tłumi wyjątku i jeśli nie zrobi się wystarczająco dużo, aby cofnąć uszkodzenie - jest to gorsze niż pozostawienie kodu w ten sposób. Podobnie samo napisanie instrukcji „log”, gdy plik jest otwarty lub błąd odczytu, może pomóc w znalezieniu przyczyny - ale z upływem czasu program może spowodować uszkodzenie danych! Nie wystarczy powiedzieć, że mam wiele prób połowu - ważniejsze jest, aby wiedzieć, co naprawdę robią!
Nie nadużywaj próby złapania.
Czasami - głównie leniwi lub naiwni programiści myślą, że po napisaniu wystarczającej liczby prób / łapań ich praca jest skończona i łatwa. Dość często najlepiej jest zastosować działanie naprawcze i wznowić, niż po prostu zrzucić całą rzecz. Jeśli nie można tego zrobić, należy zdecydować, na jakim poziomie należy wrócić. W zależności od kontekstu i wagi, spróbuj zagnieżdżenia wymaga dokładnego zaprojektowania. Na przykład - Zobacz to i to
Określ, kto jest odpowiedzialny:
Jedną z pierwszych rzeczy, które powinieneś zrobić, jest określenie, czy dane wejściowe przekazane do samej procedury są po prostu niedopuszczalnym (lub jak dotąd nieobsługiwanym) scenariuszem, czy też stanowią wyjątek ze względu na środowisko (takie jak problem z systemem, problem z pamięcią) lub czy jest to sytuacja całkowicie wewnętrzna wynikająca z wyniku algorytmu. We wszystkich przypadkach - poziom, do którego możesz wrócić lub działanie, które chcesz podjąć, różni się znacznie. W tym świetle chciałbym powiedzieć - że kiedy uruchomisz kod w środowisku produkcyjnym - wykonanie abort () do wyjścia z programu jest dobre - ale nie dla każdej drobnej rzeczy. Jeśli zauważysz uszkodzenie pamięci lub brak pamięci, to z całą pewnością nawet po zrobieniu wszystkiego, co najlepsze, wszystko umrze. Ale jeśli na wejściu pojawi się wskaźnik NULL - nie zrobiłbym tego
Zdefiniuj, co jest najlepszym możliwym rezultatem: to,
co wszystkie rzeczy muszą być zrobione z wyjątkiem, jest bardzo ważne. Na przykład, jeśli w jednym z naszych przypadków - odtwarzacz multimediów stwierdzi, że nie ma pełnych danych, które można odtworzyć dla użytkownika - co należy zrobić?
Wszystko to jest subiektywne - i być może istnieje więcej sposobów radzenia sobie z problemami niż trywialnie. Wszystkie powyższe wymagają zbudowania i zrozumienia głębi wyjątku, a także umożliwienia ewolucji różnych scenariuszy.
Czasami musimy sprawdzić wyjątki, zanim się pojawią. Najczęstszym przykładem jest błąd dzielenia przez zero. Najlepiej jest przetestować to, zanim zostanie narzucony taki wyjątek - a jeśli tak jest - spróbuj wprowadzić najbardziej odpowiednią wartość niezerową i przejść dalej, niż popaść w samobójstwo!
Sprzątać. Przynajmniej to musisz zrobić! Jeśli funkcja otworzy 3 pliki, a czwarta nie otworzy się - nie trzeba dodawać, że pierwsze 3 powinny zostać zamknięte. Delegowanie tej pracy do powyższej warstwy to zły pomysł. jeśli zdecydujesz się nie wychodzić bez czyszczenia pamięci. I najważniejsze - nawet jeśli przetrwałeś wyjątek, informuj wyżej, że sprawy nie potoczyły się normalnie.
Sposób, w jaki widzimy (normalną) funkcjonalność oprogramowania w kategoriach różnych hierarchii, warstw lub abstrakcji, w ten sam sposób musimy kategoryzować wyjątki na podstawie ich ważności, a także zakresu, w jakim powstają i wpływają na inne części systemu - które definiują jak radzić sobie z takimi wyjątkami w najlepszy możliwy sposób.
Najlepsze źródło: Code Craft rozdział 6 - dostępny do pobrania
źródło
Sprawdzanie błędów tylko podczas kompilacji debugowania to ZŁA POMYSŁ (tm), kompilacja w ramach nakładek nakładanych zmiennych wielokrotnego użytku na stosie, usuwa strony ochronne, robi niepewne sztuczki z obliczeniami, zastępuje ciężkie artretyki wstępnie obliczonymi przesunięciami i tak dalej.
Skorzystaj również ze sprawdzania błędów w wydaniu, możesz skorzystać z czegoś tak prostego, jak:
Ma to również bardzo dobry efekt uboczny, na pewno nie zignorujesz błędu, gdy aplikacja zacznie się zawieszać na betta testers PC.
Przeglądarki zdarzeń i dzienniki są całkowicie bezużyteczne w porównaniu do tego
abort()
, kto i tak je sprawdza?źródło
abort
włamuje się do debuggera / tworzy zrzut.exit
jest zły, tak. Chociaż__asm int 3
najbardziej wolę .Różne rzeczy, które możesz zrobić to: 1.
Przeczytać i przyswoić dużo kodu online i zobaczyć, jak to jest zrobione
2. Użyj niektórych narzędzi do debugowania, aby pomóc Ci zlokalizować regiony błędów
3. Bądź świadomy trywialnych błędów z powodu niewłaściwych przypisań i błędy składniowe.
4. Niektóre gorsze błędy powstają z powodu błędów logicznych w programie, które są trudniejsze do znalezienia. W tym celu możesz je wypisać i znaleźć, lub w przypadku bardziej skomplikowanych spróbuj porozmawiać z ludźmi lub skorzystać z zasobów takich jak Stackoverflow , Wikipedia , Google, aby uzyskać pomoc od ludzie.
źródło