2010-09-04 11 views

risposta

38

C'è un trucco che potrebbe essere in grado di utilizzare:

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"; 
    } 

e così via, a molti tipi differenti, come si pensa possa essere gettati. Se davvero non sai nulla di ciò che potrebbe essere lanciato allora anche il penultimo è sbagliato, perché qualcuno potrebbe lanciare uno char* che non punta a una stringa nul-terminata.

Generalmente è una cattiva idea lanciare qualsiasi cosa che non sia una classe derivata std::exception o derivata. Il motivo std::exception esiste per consentire a tutti di lanciare e catturare oggetti con cui possono fare qualcosa di utile. In un programma di giocattoli in cui vuoi solo uscire da lì e non puoi nemmeno preoccuparti di includere un'intestazione standard, OK, magari lancia un int o un valore letterale di stringa. Non penso di fare quella parte di un'interfaccia formale. Le eccezioni che fai sono parte dell'interfaccia formale, anche se in qualche modo hai dimenticato di documentarle.

+2

Ciao; questa è un'ottima risposta. Ho cercato un po 'di tempo per trovare prove nei documenti standard che questo è un comportamento standard, ma non sono stato in grado di trovarne. Sai per certo che questo è un comportamento standard? (Cioè, inserendo un nuovo 'try'-block dentro un' catch (...) {} 'e rilanciando un'eccezione per determinarne il tipo.) – NHDaly

+1

Lavorando dalla memoria: cerca il testo sulla durata del l'eccezione corrente (finché non si esce dalla clausola catch) e l'effetto di un 'throw' senza alcun operando (ripaga l'eccezione corrente). –

5

Quel blocco potrebbe catturare un int, o un const char * o altro. Come può il compilatore sapere come descrivere qualcosa quando non ne sa niente? Se si desidera ottenere informazioni su un'eccezione, è necessario conoscere il tipo.

+5

" Come può il compilatore sapere come descrivere qualcosa quando sa niente a riguardo? " - +1, ma in realtà, il compilatore ne sa qualcosa. Il meccanismo di eccezione deve memorizzare * alcune * informazioni sul tipo, perché deve corrispondere all'oggetto eccezione rispetto alle clausole catch. Ma lo standard non definisce queste informazioni né fornisce accesso ad esse, è un dettaglio di implementazione nascosto. –

+0

Queste informazioni sul tipo non sono abbastanza vicine per eseguire questa operazione e nessuna implementazione potrebbe cambiarlo. – Puppy

+1

sembra una sfida ;-) Un'estensione del compilatore '__what()' che restituisce una stringa contenente il nome typeinfo dell'eccezione corrente (facile da implementare) seguita da più caratteri che ne descrivono il valore (in pratica si potrebbe facilmente ma piuttosto noiosamente coprire tipi built-in e la maggior parte della libreria standard e forse hanno alcune implementazioni di base per i tipi definiti dall'utente). Ovviamente significherebbe che il compilatore emette un codice bloaty per ogni tipo per eseguire la sua conversione di stringhe, ma poi pensa a quanti 'operatori <<' ci sono già là fuori. Farlo per tutto, ovviamente non è possibile. –

4

Se si conosce si lancia solo std :: eccezione o sottoclassi, provare

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

In caso contrario, come ha scritto DeadMG, dal momento che si può buttare (quasi) tutto, non si può assumere nulla di quello che hai preso.

Normalmente il catch (...) deve essere utilizzato come ultima difesa quando si utilizzano librerie esterne scritte male o documentate. Quindi, si può usare una gerarchia

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

Come abbiamo le nostre eccezioni implementato è che, noi abbiamo le nostre proprie classi di eccezione, che sono tutti derivati ​​dallo std::exception ..

nostre eccezioni conterranno Messaggio di eccezione, Funzione nome, nome file e riga dove vengono generate eccezioni. Questi sono tutti utili non solo per mostrare i Messaggi, ma possono anche essere utilizzati per la registrazione che aiuta a diagnosticare l'Eccezione abbastanza facilmente. Quindi, otteniamo l'intera informazione sulle eccezioni generate.

Ricordare che le eccezioni sono per us per ottenere informazioni su cosa è andato storto. Così, ogni bit di informazione aiuta in questo senso ..

3

Dal C++ 11 è possibile catturare l'eccezione corrente con un puntatore:

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

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

Questo comporta come un puntatore intelligente; finché c'è almeno un puntatore che punta all'oggetto eccezione non viene distrutto.

Più tardi (forse anche in una funzione diversa) si può agire in un modo simile a quello attuale risposta superiore:

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

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

Citando 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

Questo non è standard o portatile. Si basa su * dettagli specifici dell'implementazione * che differiscono tra i compilatori. 'std :: exception_ptr' è un puntatore intelligente condiviso a un tipo * non specificato *, quindi non esiste alcuna garanzia che esista' __cxa_exception_type() ' –

Problemi correlati