2010-09-04 10 views
21

mogę dostać opis wyjątek złowionych przezC++ uzyskać opis wyjątek złowionych w catch (...) Blok

catch(...) 

bloku? coś w rodzaju .what() std :: exception.

+1

w C++ 11 Ponowne generowanie z ' std :: current_exception' może być użyte do otrzymania komunikatu 'what' wyjątku w bloku catch-all: http://stackoverflow.com/a/37222762/5447906 –

Odpowiedz

38

Jest jeszcze jedna sztuczka może być w stanie używać:

catch(...) { 
    handle_exception(); 
} 

void handle_exception() { 
    try { 
     throw; 
    } catch (const std::exception &e) { 
     std::cout << e.what() << "\n"; 
    } catch (const int i) { 
     std::cout << i << "\n"; 
    } catch (const long l) { 
     std::cout << l << "\n"; 
    } catch (const char *p) { 
     std::cout << p << "\n"; 
    } catch (...) { 
     std::cout << "nope, sorry, I really have no clue what that is\n"; 
    } 

i tak dalej, tak wielu różnych rodzajów, jak myślisz może zostać wyrzucony. Jeśli naprawdę nie wiesz o tym, co może zostać rzucone, to nawet ten drugi do drugiego jest zły, ponieważ ktoś może rzucić char*, który nie wskazuje na zakończony nulem ciąg.

Generalnie złym pomysłem jest wyrzucanie wszystkiego, co nie jest klasą pochodną lub klasą. Powodem, dla którego istnieje std::exception jest umożliwienie każdemu rzucania i łapania obiektów, z którymi mogą zrobić coś pożytecznego. W programie zabawkowym, w którym po prostu chcesz się stamtąd wydostać i nie możesz nawet zawracać sobie głowy umieszczaniem standardowego nagłówka, OK, może wyrzuć int lub literał łańcuchowy. Nie sądzę, żebym zrobił część interfejsu formalnego. Wszelkie wyjątki, które rzucasz, są częścią twojego oficjalnego interfejsu, nawet jeśli w jakiś sposób zapomniałeś je udokumentować.

+2

Witam; to jest świetna odpowiedź. Szukałem trochę czasu, aby znaleźć w dokumentach normalnych dowody na to, że jest to standardowe zachowanie, ale nie udało się go znaleźć. Czy wiesz na pewno, że jest to standardowe zachowanie? (To znaczy, wprowadzanie nowego 'try'-bloku wewnątrz' catch (...) {} 'i ponowne wyrzucanie wyjątku w celu określenia jego typu.) – NHDaly

+1

Praca z pamięci: poszukaj tekstu o czasie życia bieżący wyjątek (dopóki nie wyjdziesz z klauzuli catch) i efekt 'throw' bez operandu (ponownie wyświetla bieżący wyjątek). –

5

Ten blok może przechwycić int, const char * lub cokolwiek innego. W jaki sposób kompilator może wiedzieć, jak opisać coś, gdy nic o nim nie wie? Jeśli chcesz uzyskać informacje poza wyjątkiem, musisz znać typ.

+5

" W jaki sposób kompilator może wiedzieć, jak opisać coś, gdy wie nic na ten temat? " - +1, ale w rzeczywistości kompilator trochę o tym wie. Mechanizm wyjątków musi przechowywać * trochę * informacji o typie, ponieważ musi dopasować obiekt wyjątku do klauzul catch. Ale standard nie definiuje tych informacji ani nie zapewnia dostępu do nich, jest to ukryty szczegół implementacji. –

+0

Informacje tego typu nie są wystarczająco bliskie, aby wykonać tę operację, a żadna implementacja nie może tego zmienić. – Puppy

+1

brzmi jak wyzwanie ;-) Rozszerzenie kompilatora '__what()', które zwraca ciąg znaków zawierający nazwę typu infoinfo bieżącego wyjątku (łatwe do implementacji), po którym następuje więcej znaków opisujących jego wartość (w praktyce można łatwo, ale żmudnie zakryć typy wbudowane i większość biblioteki standardowej, i być może mają podstawowe implementacje dla typów zdefiniowanych przez użytkownika). Oczywiście oznaczałoby to, że kompilator emituje jakiś rozdęty kod dla każdego typu, aby wykonać konwersję ciągów, ale potem pomyśl, ile 'operatora <<' już tam jest. Robienie tego za wszystko, oczywiście nie jest możliwe. –

4

Jeśli wiesz tylko rzucać std :: exception lub podklasy, spróbuj

catch(std::exception& e) {...e.what()... } 

przeciwnym razie, jak DeadMG napisał, ponieważ można rzucać (prawie) wszystko, nie można nic na temat tego, co złowione zakładać.

Zwykle catch (...) powinien być używany tylko jako ostatnia opcja obrony przy użyciu źle napisanych lub udokumentowanych bibliotek zewnętrznych. Więc można używać hierarchię

catch(my::specialException& e) { 
     // I know what happened and can handle it 
     ... handle special case 
     } 
catch(my::otherSpecialException& e) { 
     // I know what happened and can handle it 
     ... handle other special case 
     } 
catch(std::exception& e) { 
     //I can at least do something with it 
     logger.out(e.what()); 
     } 
catch(...) { 
    // something happened that should not have 
    logger.out("oops"); 
    } 
2

Jak mamy wyjątki realizowany jest to, że mamy własne klasy wyjątku, które są pochodzące z std::exception ..

Nasze wyjątki będą zawierać wiadomość wyjątku Function nazwa, nazwa pliku i linia gdzie generowane są wyjątki. Są one użyteczne nie tylko do wyświetlania komunikatów, ale mogą być również wykorzystywane do rejestrowania logowania, co pomaga w dość łatwym zdiagnozowaniu wyjątku. Otrzymujemy całą informację o wygenerowanych wyjątkach.

Pamiętaj, wyjątki są dla nas, aby uzyskać informacje o tym, co poszło nie tak. Tak więc, każdy bit informacji pomaga w tym zakresie ..

3

Ponieważ C++ 11 można uchwycić bieżący wyjątek ze wskaźnikiem:

std::exception_ptr p;  // default initialization is to nullptr 

try { 
     throw 7; 
} 
catch(...) 
{ 
    p = std::current_exception(); 
} 

ten zachowuje się jak inteligentnego wskaźnika; o ile istnieje co najmniej jeden wskaźnik wskazujący na obiekt wyjątku, nie jest on niszczony.

później (być może nawet w innej funkcji) można podjąć działania w sposób podobny do obecnego górnym odpowiedź:

try { 
    if (p) 
     std::rethrow_exception(p); 
} 
catch(int x) 
{ 

} 
catch(std::exception &y) 
{ 
} 
2

Cytowanie bobah

#include <iostream> 

#include <exception> 
#include <typeinfo> 
#include <stdexcept> 

int main() 
{ 
    try { 
     throw ...; // throw something 
    } 
    catch(...) 
    { 
     std::exception_ptr p = std::current_exception(); 
     std::clog <<(p ? p.__cxa_exception_type()->name() : "null") << std::endl; 
    } 
    return 1; 
} 
+1

To nie jest standardowe ani przenośne. Opiera się na * szczegółach specyficznych dla implementacji *, które różnią się między kompilatorami. 'std :: exception_ptr' jest inteligentnym wspólnym wskaźnikiem do * nieokreślonego * typu, więc nie ma gwarancji, że istnieje' __cxa_exception_type() ' –

Powiązane problemy