2015-01-13 9 views
48

Non sono sicuro se questo è un problema con il compilatore o se sto facendo qualcosa di sbagliato. Sto usando il compilatore di Visual Studio 2013.Costruttore come blocco try di una funzione - Programma di interruzione di eccezioni

Ho una classe in cui ho bisogno di acquisire una quantità significativa di risorse nel mio elenco di inizializzatore costruttore la maggior parte delle quali può generare un'eccezione. Ho concluso l'elenco di inizializzazione dei membri in un blocco di prova della funzione e ho rilevato l'eccezione lì. Ma il mio programma abortisce anche se la clausola catch non rigenera l'eccezione. Non sono autorizzato a pubblicare il codice effettivo. Quindi ho riprodotto il problema con questo codice demo equivalente. Qualcuno può aiutarmi ad aiutarmi?

#include <iostream> 
using namespace std; 
class A{ 
public: 
    A() try : i{ 0 }{ throw 5; } 
    catch (...){ cout << "Exception" << endl; } 
private: 
    int i; 
}; 


int main(){ 
    A obj; 
} 

Durante l'esecuzione di questo codice viene visualizzato un avviso di Windows "abort() è stato chiamato". Quindi immagino che il sistema lo tratti come un'eccezione non rilevata e che chiama terminate().

D'altra parte se avvolgo la costruzione dell'oggetto in main() in un blocco try-catch, l'eccezione viene rilevata correttamente e il programma termina normalmente.

Qualcuno può dirmi se sto facendo qualcosa di sbagliato qui?

+4

sguardo http://www.gotw.ca/gotw/066.htm per una discussione su questo problema –

+0

Grazie mille Jan Herrmann. Ovviamente lo standard ha molto senso affermare che se un'eccezione non viene rimessa in gioco o se una nuova eccezione non viene lanciata dalla funzione, prova il blocco del costruttore, quindi verrà automaticamente retrocesso alla fine del blocco catch. Questo ha perfettamente senso ora. Forse come l'idioma pimpl suggerito è quello che dovrei iniziare a usare. Grazie mille ancora – Madhusudhan

+20

Punti extra per * "Non sono autorizzato a pubblicare il codice effettivo. Così ho riprodotto il problema con questo codice demo equivalente. "* Hai fatto un ottimo [MCVE] (https://stackoverflow.com/help/mcve). – 5gon12eder

risposta

30

C'è un GotW rilevante

http://gotw.ca/gotw/066.htm

In sostanza, anche se non si butta nel blocco catch, l'eccezione verrà automaticamente rilanciati

Se il corpo del gestore conteneva l'affermazione " gettare;" quindi il blocco catch riporterà ovviamente qualsiasi eccezione A :: A() o B :: B() ha emesso . Ciò che è meno ovvio, ma chiaramente indicato nello standard, è che se il blocco catch non gira (o rilancia l'eccezione originale o lancia qualcosa di nuovo), e il controllo raggiunge la fine del blocco di cattura di un costruttore o distruttore , quindi l'eccezione originale viene automaticamente ripristinata.

+0

Quella pagina è una lettura davvero eccellente. Non sapevo che la sintassi della funzione try-block esistesse prima di questa domanda; imparato molto da questo link! In particolare, c'è un'analogia fantastica: "Se la costruzione di qualsiasi oggetto base o membro fallisce, l'intero oggetto * deve * fallire ... nessun modo per un essere umano di [nascere] se uno qualsiasi degli organi vitali non fosse mai formato". – OJFord

+0

l'intero sito Web gotw è una miniera d'oro per qualsiasi sviluppatore C++! Insieme al sito web di Bjarne, parashift, cppreference e cplusplus –

+0

ho scoperto proprio questo nei 48 minuti dal mio commento sopra! Una vergogna più recente è stata l'1/1/08. – OJFord

22

Questo è un comportamento normale secondo the cppreference.com documentation for function-try blocks: un cosiddetto function-try-block su un costruttore o distruttore deve gettare dalla sua cattura-clausola o altro v'è una rethrow implicita dopo la cattura-clausola.

Questo ha perfettamente senso: l'oggetto A non è stato costruito correttamente e quindi non è in uno stato adatto all'uso: deve generare un'eccezione. È necessario verificare se la costruzione è riuscita nel luogo in cui l'oggetto è costruito, vale a dire nel caso del proprio esempio in main().

+4

Fare l'upvoting perché questa risposta ha una risposta più leggibile rispetto a quella standard quotata. Per l'OP: il tuo problema è che uno o più dei tuoi membri sono in uno stato non costruito (dato che non sai quale costruzione del membro ha gettato, non sai quali membri sono stati interamente costruiti). Quindi la tua classe non è completamente costruita. Averlo rethrow garantisce che non puoi usare questa istanza. I membri che sono stati completamente costruiti verranno opportunamente distrutti. –

9

Non è possibile rilevare eccezioni nel costruttore function-try-block.

n3376 15,2/15

L'eccezione attualmente gestita viene rilanciati se il controllo raggiunge la fine di un gestore della funzione-provare-a blocchi di un costruttore o distruttore.

Si dovrebbe catturarlo nel luogo di creazione dell'oggetto.

Problemi correlati