2010-04-26 18 views
5

Se un distruttore getta in C++ durante lo srotolamento dello stack causato da un'eccezione, il programma termina. (Ecco perché distruttori non dovrebbero mai gettare in C++.) Esempio:Lancio di una nuova eccezione durante il lancio di una vecchia eccezione

struct Foo 
{ 
    ~Foo() 
    { 
     throw 2; // whoops, already throwing 1 at this point, let's terminate! 
    } 
}; 

int main() 
{ 
    Foo foo; 
    throw 1; 
} 

terminate called after throwing an instance of 'int' 

This application has requested the Runtime to terminate it in an unusual way. 
Please contact the application's support team for more information. 

Se viene inserito un blocco finally in Java a causa di un'eccezione nel blocco try corrispondente e che finalmente blocco lancia una seconda eccezione, la prima eccezione è inghiottito silenziosamente. Esempio:

public static void foo() throws Exception 
{ 
    try 
    { 
     throw new Exception("first"); 
    } 
    finally 
    { 
     throw new Exception("second"); 
    } 
} 

public static void main(String[] args) 
{ 
    try 
    { 
     foo(); 
    } 
    catch (Exception e) 
    { 
     System.out.println(e.getMessage()); // prints "second" 
    } 
} 

Questa domanda mi attraversò la mente: in grado di gestire un linguaggio di programmazione più eccezioni gettati allo stesso tempo? Sarebbe utile? Hai mai perso quell'abilità? C'è un linguaggio che già supporta questo? C'è qualche esperienza con un simile approccio?

Qualche idea?

+7

Hai appena fatto il mio cervello lanciare un'eccezione –

+1

Interessante domanda. Presumo che "gestendo un'eccezione" si intenda specificamente "stack unwinding a causa di un'eccezione", non "esecuzione di codice da un blocco catch". Quest'ultimo chiamerei "gestire un'eccezione", ma dal momento che un gestore è stato localizzato, è possibile generare un'eccezione da lì (almeno in C++). –

+0

@Nick Hai ragione, ho modificato il titolo.Se ne conosci uno migliore, sentiti libero di cambiarlo di nuovo ;-) – fredoverflow

risposta

5

Pensare in termini di controllo del flusso. Le eccezioni sono fondamentalmente solo fantasia setjmp/longjmp o setcc/callcc.L'oggetto eccezione viene utilizzato per selezionare un particolare luogo in cui saltare, come un indirizzo. Il gestore eccezioni ricorre semplicemente all'eccezione corrente, longjmp finché non viene gestita.

La gestione di due eccezioni alla volta è semplicemente una questione di raggrupparle in una, in modo che il risultato produca un controllo di flusso coerente. Posso pensare a due alternative:

  • Combinarle in un'eccezione non stampabile. Sarebbe come srotolare l'intero stack e ignorare tutti i gestori. Ciò crea il rischio di un'eccezione a cascata che provoca un comportamento totalmente casuale.
  • In qualche modo costruire il loro prodotto cartesiano. Si, come no.

La metodologia C++ è utile nell'interesse della prevedibilità.

0

Sì, è possibile che una lingua supporti il ​​lancio di più eccezioni alla volta; tuttavia, ciò significa anche che i programmatori devono gestire più eccezioni alla volta, quindi c'è sicuramente un compromesso. Ho sentito parlare di lingue che hanno questo anche se ho difficoltà a venire con la lista dalla cima della mia testa; Credo che LINQ o PLINQ possano essere una di quelle lingue, ma non me ne ricordo abbastanza. In ogni caso, ci sono diversi modi in cui possono essere lanciate più eccezioni ... un modo è usare il concatenamento delle eccezioni, forzando un'eccezione a diventare la "causa" o "previousProgatingException" dell'altro, oppure imbottendo tutte le eccezioni in un'unica eccezione che rappresenta il fatto che sono state lanciate più eccezioni. Suppongo che un linguaggio possa anche introdurre una clausola catch che ti permetta di specificare più tipi di eccezioni contemporaneamente, anche se questa sarebbe una scelta di design scarsa, IMHO, dato che il numero di handler è abbastanza grande così com'è, e che risulterebbe in un'esplosione di prendere le clausole solo per gestire ogni singola combinazione possibile.

2

Un linguaggio di programmazione può gestire più eccezioni? Certo, non vedo perché no. Sarebbe utile? No, direi che non lo sarebbe. La gestione e la ripresa degli errori è molto difficile - non vedo come l'aggiunta dell'esplosione combinatoria al problema possa aiutare le cose.

3

È possibile concatenare eccezioni. http://java.sun.com/docs/books/tutorial/essential/exceptions/chained.html

try { 

} catch (IOException e) { 
    throw new SampleException("Other IOException", e); 
} 

Si può anche avere un tentativo di cattura all'interno del vostro finnally troppo.

try{ 
}catch(Exception e){ 
}finally{ 
    try{ 
     throw new SampleException("foo"); 
    }catch(Exception e){ 
    } 
} 

Edit:

Inoltre è possibile avere più catture. Non credo che più eccezioni sarebbero una buona idea, perché un'eccezione è già qualcosa da cui devi recuperare. L'unica ragione per avere più di un'eccezione a cui riesco a pensare è se la si utilizza come parte della propria logica (come i ritorni multipli), il che sarebbe deviante dallo scopo originario dell'idea dell'eccezione. Inoltre, come si possono produrre due eccezioni allo stesso tempo?

+0

Credo che C# permetta anche il concatenamento. Mi chiedo se C++ 0x consentirà il concatenamento? –

+0

Questo è consentito in tutto il C++. Il problema C++ dichiarato da OP non è correlato. – Potatoswatter

0

C++ std :: exception_ptr consente di memorizzare eccezioni. Quindi dovrebbe essere possibile incorporare eccezioni in altre eccezioni e darti l'impressione di avere lo stack su eccezioni generate. Questo potrebbe essere utile se si desidera conoscere la causa principale dell'eccezione effettiva.

+0

Questo vale per le eccezioni generate all'interno di un blocco 'catch'. Le eccezioni lanciate dai distruttori durante lo svolgersi sono una bestia diversa. – Potatoswatter

+0

Lo so. Ma la domanda non è legata a questo, è solo un'introduzione alla domanda finale. –

0

Una situazione in cui molteplici eccezioni generate in parallelo potrebbe essere utile, è unit test con JUnit:

  • Se un test fallisce, viene generata un'eccezione (prodotta dalla codice sotto test o un'asserzione).
  • Ogni metodo @After viene richiamato dopo il test, indipendentemente dal fatto che il test abbia esito negativo o abbia esito positivo.
  • Se un metodo After non riesce, viene generata un'altra eccezione.
  • Solo l'eccezione generata nel metodo Dopo viene visualizzata nel mio IDE (Eclipse) per il risultato del test.

so che JUnit notifica gli ascoltatori di test su entrambe le eccezioni, e quando il debug di un test in Eclipse posso vedere la prima eccezione che appare nella vista JUnit, solo per essere sostituita dalla seconda eccezione poco dopo.

Questo problema dovrebbe probabilmente essere risolto facendo in modo che Eclipse ricordi tutte le notifiche per un determinato test, non solo l'ultimo. Avendo "eccezioni parallele", in cui l'eccezione da finally non inghiotte quella da try, risolverebbe anche questo problema.

0

Se ci pensi, la situazione che hai descritto ha Exception("First") come la causa principale di Exception("second"), concettualmente. La cosa più utile per l'utente sarebbe probabilmente ottenere un dump dello stack che mostri una catena in questo ordine ...

0

Nelle piattaforme gestite, posso pensare a situazioni in cui potrebbe essere utile avere un disposer "elevare" un eccezione a qualcosa che è più forte, ma non totalmente fatale per un'applicazione. Ad esempio, un dissipatore di oggetti "comando" potrebbe tentare di srotolare lo stato della sua connessione associata per annullare eventuali comandi parzialmente eseguiti. Se funziona, il codice sottostante potrebbe tentare di fare altre cose con la connessione. Se il tentativo di "annullare" non funziona, l'eccezione dovrebbe probabilmente propagarsi al livello in cui la connessione sarebbe stata distrutta. In tal caso, può essere utile che l'eccezione contenga una "eccezione interna", anche se l'unico modo per ottenerlo sarebbe quello di tentare lo srotolamento in un blocco catch piuttosto che in un blocco "finally".

Problemi correlati