Czy istnieje odpowiednik języka Java w języku C ++?
try {
...
}
catch (Throwable t) {
...
}
Próbuję debugować kod Java / jni, który wywołuje rodzime funkcje systemu Windows, a maszyna wirtualna ulega awarii. Kod macierzysty pojawia się dobrze w testach jednostkowych i wydaje się zawieszać tylko po wywołaniu przez jni. Ogólny mechanizm wychwytywania wyjątków okazałby się niezwykle przydatny.
Odpowiedzi:
wyłapie wszystkie wyjątki w C ++, ale należy to uznać za zły projekt. Możesz użyć nowego mechanizmu wyjątku current_exception c ++ 11, ale jeśli nie masz możliwości korzystania z c ++ 11 (starsze systemy kodowe wymagające przepisania), to nie masz wskazanego wskaźnika wyjątku, aby użyć wiadomości lub nazwy . Możesz dodać osobne klauzule catch dla różnych wyjątków, które możesz przechwycić, i łap tylko wszystko na dole, aby zarejestrować nieoczekiwany wyjątek. Na przykład:
źródło
Ktoś powinien dodać, że nie można złapać „awarii” w kodzie C ++. Nie rzucają wyjątków, ale robią wszystko, co im się podoba. Gdy widzisz, że program ulega awarii z powodu odwołania się do wskaźnika zerowego, zachowuje się w sposób niezdefiniowany. Nie ma
std::null_pointer_exception
. Próba wyłapania wyjątków nie pomoże.Na wszelki wypadek ktoś czyta ten wątek i myśli, że może uzyskać przyczynę awarii programu. Zamiast tego należy użyć debugera, takiego jak gdb.
źródło
try { .. } catch(...) { ... }
przechwytywania za pomocą sygnału / sigaction, nie nazwałbym tego „przechwytywaniem” :) Jeśli w procedurze obsługi sygnału, programiście stosunkowo trudno jest wiedzieć, gdzie w kodzie doszło do awarii (mówię o programowym wykrywaniu tego), w porównaniu do try / catch.Oto, w jaki sposób możesz dokonać inżynierii wstecznej typu wyjątku od wewnątrz,
catch(...)
jeśli zajdzie taka potrzeba (może być przydatny podczas przechwytywania nieznanego z biblioteki innej firmy) za pomocą GCC:a jeśli możesz sobie pozwolić na korzystanie ze wzmocnienia , możesz uczynić sekcję catch jeszcze prostszą (na zewnątrz) i potencjalnie międzyplatformową
źródło
Zauważ, że
...
wnętrzecatch
jest prawdziwą elipsą, tj. trzy kropki.Ponieważ jednak wyjątki w C ++ niekoniecznie są podklasami
Exception
klasy podstawowej , nie ma żadnego sposobu, aby zobaczyć zmienną wyjątku, która jest generowana podczas korzystania z tej konstrukcji.źródło
catch
specyfikator od istniejącego symbolu zastępczego kodu w komentarzu (// ...
), który oczywiście nie jest składnią C ++.nie jest możliwe (w C ++) wyłapanie wszystkich wyjątków w przenośny sposób. Jest tak, ponieważ niektóre wyjątki nie są wyjątkami w kontekście C ++. Obejmuje to między innymi dzielenie przez zero błędów i inne. Możliwe jest włamanie się i uzyskanie możliwości rzucania wyjątków, gdy wystąpią te błędy, ale nie jest to łatwe i na pewno nie jest łatwo dostać się w przenośny sposób.
Jeśli chcesz złapać wszystkie wyjątki STL, możesz to zrobić
Który pozwoli ci użyć
e.what()
, który zwróci aconst char*
, która może powiedzieć ci więcej o samym wyjątku. Jest to konstrukcja, która najbardziej przypomina konstrukcję Java.Nie pomoże ci to, jeśli ktoś jest na tyle głupi, aby rzucić wyjątek, który nie dziedziczy
std::exception
.źródło
Krótko mówiąc, użyj
catch(...)
. Należy jednak pamiętać, żecatch(...)
należy go używać w połączeniu zthrow;
:To jest właściwy sposób użycia
catch(...)
.źródło
Foo
destruktor? Myślałem, że o to właśnie chodzi w RAII. Jeśli jednak potrzebujesz wskaźnika doFoo
raczej niż tylko tworzeniaFoo
stosu, musisz owinąć wskaźnik w coś innego, co zadeklarowano na stosie.można to zrobić pisząc:
Istnieje jednak bardzo niezauważalne ryzyko: nie można znaleźć dokładnego rodzaju błędu, który został zgłoszony w
try
bloku, więc skorzystaj z tego rodzaju,catch
gdy masz pewność, że bez względu na rodzaj wyjątku program musi pozostać w sposób określony wcatch
bloku.źródło
Możesz użyć
ale to jest bardzo niebezpieczne. W swojej książce Debugowanie systemu Windows John Robbins opowiada historię wojenną o naprawdę paskudnym błędzie, który został zamaskowany poleceniem catch (...). Lepiej złapać określone wyjątki. Złap wszystko, co Twoim zdaniem blok try może rzucić, ale niech kod wyrzuci wyjątek wyżej, jeśli wydarzy się coś naprawdę nieoczekiwanego.
źródło
Pozwól mi tylko wspomnieć o tym tutaj: Java
NIE może złapać wszystkich wyjątków! W rzeczywistości zdarzyło mi się wcześniej, że takie rzeczy się zdarzają i jest to bardzo prowokujące; Wyjątek pochodzi od Throwable. Więc dosłownie, aby złapać wszystko, NIE CHCESZ uchwycić wyjątków; chcesz złapać Throwable.
Wiem, że to brzmi podejrzanie, ale kiedy spędziłeś kilka dni próbując dowiedzieć się, skąd pochodzi „nieprzechwycony wyjątek” w kodzie otoczonym blokiem try ... catch (Exception e) ", pozostaje przy ty.
źródło
catch(Exception)
może nie wychwycić wszystkich wyjątków w Javie, mieszasz się z C # ... Java =catch(Thowable)
, C # =catch(Exception)
. Nie pomyl ich.CoderMalfunctionError
(która w rzeczywistości jest prawdziwąError
podklasą Java ... chociaż to nie znaczy, jak to brzmi.)Cóż, jeśli chcesz złapać cały wyjątek, aby na przykład utworzyć minidump ...
Ktoś wykonał pracę w systemie Windows.
Zobacz http://www.codeproject.com/Articles/207464/Exception-Handling-in-Visual-Cplusplus W artykule wyjaśnia, w jaki sposób dowiedział się, jak wychwycić wszelkiego rodzaju wyjątki, i podaje kod, który działa.
Oto lista, którą możesz złapać:
I zastosowanie: CCrashHandler ch; ch.SetProcessExceptionHandlers (); // zrób to dla jednego wątku ch.SetThreadExceptionHandlers (); // za każdy thred
Domyślnie tworzy to minidump w bieżącym katalogu (crashdump.dmp)
źródło
Wątpliwy. Wiesz już, że Twój kod jest uszkodzony, ponieważ ulega awarii. Wyjątki od jedzenia mogą to maskować, ale prawdopodobnie spowoduje to jeszcze bardziej paskudne, subtelniejsze błędy.
To, czego naprawdę chcesz, to debugger ...
źródło
Czy możesz uruchomić aplikację Java korzystającą z JNI z okna konsoli (uruchomić ją z wiersza poleceń Java), aby sprawdzić, czy istnieje raport o tym, co mogło zostać wykryte przed awarią JVM. Podczas uruchamiania bezpośrednio jako aplikacja do okna Java może brakować komunikatów, które pojawiłyby się, gdyby zamiast tego uruchomić z okna konsoli.
Po drugie, czy możesz wyciąć implementację biblioteki DLL JNI, aby pokazać, że metody w bibliotece DLL są wprowadzane z JNI, zwracasz poprawnie itp.?
Na wypadek, gdyby problem dotyczył nieprawidłowego użycia jednej z metod interfejsu JNI z kodu C ++, czy sprawdziłeś, czy niektóre proste przykłady JNI kompilują się i pracują z twoją instalacją? W szczególności myślę o użyciu metod interfejsu JNI do konwersji parametrów na natywne formaty C ++ i zamiany wyników funkcji na typy Java. Przydatne jest wytarcie tych, aby upewnić się, że konwersje danych działają i nie będziesz szaleć w wywołaniach typu COM w interfejsie JNI.
Są inne rzeczy do sprawdzenia, ale trudno je zasugerować, nie wiedząc więcej o tym, jakie są twoje rodzime metody Java i jakie są ich implementacje JNI. Nie jest jasne, czy wyłapanie wyjątku z poziomu kodu C ++ jest związane z twoim problemem. (Możesz użyć interfejsu JNI, aby ponownie wprowadzić wyjątek jako Java, ale z tego, co podasz, nie wynika jasno, że to pomoże).
źródło
Dla prawdziwego problemu związanego z niemożnością poprawnego debugowania programu korzystającego z JNI (lub błąd nie pojawia się podczas uruchamiania go w debugerze):
W takim przypadku często pomaga dodać owijki Java wokół wywołań JNI (tj. Wszystkie metody rodzime są prywatne, a metody publiczne w klasie wywołują je), które wykonują podstawowe sprawdzenie poprawności (sprawdzają, czy wszystkie „obiekty” są zwolnione, a „obiekty” nie są używane po zwolnieniu) lub synchronizacji (wystarczy zsynchronizować wszystkie metody z jednej biblioteki DLL do instancji pojedynczego obiektu). Pozwól metodom otoki Java zarejestrować błąd i zgłosić wyjątek.
Pomoże to często znaleźć prawdziwy błąd (który jest zaskakujący głównie w kodzie Java, który nie przestrzega semantyki wywoływanych funkcji, powodując nieprzyjemne podwójne zwolnienia lub podobne) łatwiej niż próba debugowania masowo równoległego programu Java w natywny debugger ...
Jeśli znasz przyczynę, zachowaj kod w metodach opakowania, które go unikają. Lepiej, aby Twoje metody pakowania zgłaszały wyjątki, niż kod JNI powoduje awarię maszyny wirtualnej ...
źródło
To zależy od środowiska kompilatora. gcc ich nie łapie. Visual Studio i ostatni Borland, którego użyłem.
Wniosek dotyczący awarii jest taki, że zależy to od jakości środowiska programistycznego.
Specyfikacja C ++ mówi, że catch (...) musi przechwytywać wszelkie wyjątki, ale nie we wszystkich przypadkach.
Przynajmniej z tego, co próbowałem.
źródło
Być świadomym
wyłapuje tylko wyjątki na poziomie języka, inne wyjątki / błędy niskiego poziomu, takie jak
Access Violation
iSegmentation Fault
nie zostaną złapane.źródło