2016-03-29 19 views
6

http://ideone.com/UtVzxwProva sintassi cattura costruttore

struct base 
{ 
    base() { throw std::exception(); } 
}; 

struct derived : public base 
{ 
    derived() try : base() { } 

    catch (std::exception& e) 
    { 
     std::cout << "exception handled" << std::endl; 
    } 
}; 

int main() 
{ 
    derived a; // My app crashes. 
    return 0; 
} 

Shoun't mio app di scrittura "eccezione gestita" e prosegue la marcia?

L'unica soluzione che ho trovato è di circondare la costruzione di "a" in un blocco try/catch. Ma se lo faccio, qual è il punto di avere il try/catch nel costruttore al primo posto? Suppongo che il suo uso sia ripulire le variabili membro che potrebbero essere state allocate? dal momento che il distruttore non viene chiamato?

Il seguente funziona, ma gestisce l'eccezione 2 volte.

struct base 
{ 
    base() { throw std::exception(); } 
}; 

struct derived : public base 
{ 
    derived() try : base() { } 

    catch(std::exception& e) 
    { 
     std::cout << "exception 1" << std::endl; 
    } 
}; 

int main() 
{ 
    // This works fine. 
    try { 
     derived a; 
    } 
    catch(std::exception& e) 
    { 
     std::cout << "exception 2" << std::endl; 
    } 
    return 0; 
} 

Sto solo cercando di chiedere a me stesso perché non dovrei semplicemente schivare la sintassi try/catch per il costruttore e scrivere questo:

struct base 
{ 
    base() { throw std::exception(); } 
}; 

struct derived : public base 
{ 
    derived() : base() { } 
}; 

int main() 
{ 
    // This works fine. 
    try { 
     derived a; 
    } 
    catch(std::exception& e) 
    { 
     std::cout << "exception handled" << std::endl; 
    } 
    return 0; 
} 

risposta

7

funzione-try-block nella funzione di costruzione non impedisce l'esecuzione dell'eccezione. Ecco un estratto dal C++ progetto di norma N4140, [except.handle]:

14 Se una dichiarazione di ritorno appare in un gestore della function-try-block di un costruttore, il programma è mal-formata.

15 L'eccezione attualmente gestita viene rilanciati se il controllo raggiunge la fine di un gestore della function-try-block di un costruttore o distruttore. Altrimenti, ...

La ragione di ciò è che se la classe base o qualsiasi costruttore membro genera un'eccezione, la costruzione dell'intero oggetto non riesce e non c'è modo di risolverlo, quindi l'eccezione deve essere gettato.

C'è un GOTW su questo, e il fondo è

gestori Constructor function-try-block hanno un solo scopo - di tradurre un'eccezione. (E forse per fare il logging o qualche altro effetto collaterale.) Non sono utili per nessun altro scopo.

Quindi, sì, l'ultimo esempio di codice è perfettamente a posto.

+0

Quindi supponiamo che tu sia Google che ha la politica di non usare le eccezioni e hai trovato una biblioteca interessante, ma la classe che vuoi ereditare da una serie (solo nel costruttore, non altrove). Se ne erediti, ogni persona che usa la classe derivata deve usare try/catch ogni volta. Cosa faresti in questo caso? Sembra che l'unica risposta sia: usare un'altra libreria, solo a causa del costruttore ... – James

+0

@Phantom o non ereditarlo, fare un puntatore ad esso un membro e inizializzarlo nel corpo del costruttore. Ma credo che in Google non ti permetteranno comunque di usare quella libreria. –

3

Wrapping un try/catch intorno il costruttore di una superclasse ti permette di intercettare le eccezioni che vengono lanciate nel costruttore della superclasse; tuttavia l'eccezione viene automaticamente ripristinata quando termina il blocco catch e l'eccezione continua a propagarsi.

Dopo tutto, la superclasse non è stata costruita. Ha lanciato un'eccezione. Quindi non puoi davvero continuare sulla tua strada allegra, nel costruttore della sottoclasse, e poi finire con una sottoclasse costruita, ma con una superclasse che non è stata costruita. Non ha senso.

Da http://en.cppreference.com/w/cpp/language/function-try-block:

Lo scopo principale della funzione-provare-blocchi è accedere o modificare, e poi rigenerare le eccezioni sollevate dalla lista di inizializzazione membro in un costruttore. Vengono raramente utilizzati con i distruttori o con le normali funzioni .

Questo è davvero il valore aggiunto primario di blocchi funzione da provare: un posto comodo per registrare "hey, questa funzione ha generato un'eccezione", che abbraccia l'intera funzione, un unico luogo per registrare questo tipo di cosa, ma senza influire sulla normale gestione delle eccezioni.