To, co wydaje się, że Cię złapano, to piekło kogoś, kto próbuje zjeść swoje ciasto i je zjeść.
RAII i wyjątki są zaprojektowane tak, aby iść w parze. RAII to sposób, w jaki nie trzeba pisać wielu catch(...)
instrukcji, aby wykonać czyszczenie. Oczywiście stanie się to automatycznie. Wyjątki są jedynym sposobem pracy z obiektami RAII, ponieważ konstruktory mogą odnieść sukces lub wyrzucić (lub wprowadzić obiekt w stan błędu, ale kto tego chce?).
catch
Oświadczenie może zrobić jedną z dwóch rzeczy: obsługiwać błąd lub wyjątkową okoliczność, czy prac porządkowych. Czasami robi to obie, ale każde catch
oświadczenie istnieje, aby wykonać przynajmniej jedną z nich.
catch(...)
nie jest w stanie poprawnie obsługiwać wyjątków. Nie wiesz jaki jest wyjątek; nie możesz uzyskać informacji o wyjątku. Nie masz absolutnie żadnych informacji poza faktem, że wyjątek został zgłoszony przez coś w pewnym bloku kodu. Jedyną uzasadnioną rzeczą, jaką możesz zrobić w takim bloku, jest wyczyszczenie. A to oznacza ponowne zgłoszenie wyjątku na koniec czyszczenia.
To, co RAII oferuje w odniesieniu do obsługi wyjątków, to bezpłatne czyszczenie. Jeśli wszystko jest poprawnie zamknięte w RAII, wszystko zostanie odpowiednio wyczyszczone. Nie musisz już mieć catch
instrukcji do czyszczenia. W takim przypadku nie ma powodu, aby pisać catch(...)
oświadczenie.
Zgadzam się więc, że catch(...)
to głównie zło ... tymczasowo .
Przepis ten dotyczy właściwego wykorzystania RAII. Ponieważ bez niego musisz być w stanie wykonać pewne porządki. Nie można tego obejść; musisz być w stanie wykonać prace porządkowe. Musisz mieć pewność, że zgłoszenie wyjątku pozostawi kod w rozsądnym stanie. I catch(...)
jest do tego niezbędnym narzędziem.
Nie możesz mieć jednego bez drugiego. Nie można powiedzieć, że zarówno RAII, jak i catch(...)
są złe. Potrzebujesz co najmniej jednego z nich; w przeciwnym razie nie jesteś wyjątkowo bezpieczny.
Oczywiście istnieje jedno ważne, choć rzadkie zastosowanie, catch(...)
którego nawet RAII nie może odrzucić: exception_ptr
skierowanie do kogoś innego. Zazwyczaj za pośrednictwem promise/future
podobnego interfejsu.
Moi współpracownicy mówią, że zawsze powinieneś wiedzieć, jakie wyjątki mają być zgłaszane i że zawsze możesz używać konstrukcji takich jak:
Twój współpracownik jest idiotą (lub po prostu strasznie ignorantem). Powinno to być natychmiast oczywiste ze względu na to, ile kodu kopiuj i wklej sugeruje, abyś napisał. Czyszczenie każdej z tych instrukcji catch będzie dokładnie takie samo . To koszmar konserwacji, nie wspominając o czytelności.
W skrócie: jest to problem, który RAII stworzono do rozwiązania (nie dlatego, że nie rozwiązuje on innych problemów).
To, co mnie dezorientuje w tym pojęciu, to fakt, że zasadniczo jest to odwrotne do tego, jak większość ludzi twierdzi, że RAII jest zły. Ogólnie argumentem jest, że „RAII jest zły, ponieważ musisz użyć wyjątków, aby zasygnalizować awarię konstruktora. Ale nie możesz rzucać wyjątków, ponieważ nie jest to bezpieczne i będziesz musiał mieć wiele catch
instrukcji, aby wszystko wyczyścić”. Co jest zepsutym argumentem, ponieważ RAII rozwiązuje problem, który powoduje brak RAII.
Jest bardziej niż prawdopodobne, że jest przeciwko RAII, ponieważ ukrywa szczegóły. Wywołania niszczycieli nie są natychmiast widoczne w zmiennych automatycznych. Otrzymujesz kod, który jest wywoływany niejawnie. Niektórzy programiści naprawdę tego nie znoszą. Najwyraźniej do tego stopnia, że uważają, że posiadanie 3 catch
instrukcji, z których wszystkie robią to samo z kodem kopiuj i wklej, jest lepszym pomysłem.
...
”, a moje pytanie nacisk na „Powinienem lepiej złapać...
lub<specific exception>
przed Ponowne generowanie”