2015-09-01 25 views
6

Allora avremo UB? Ho provato questo:Cosa succede se un costruttore lancia un'eccezione?

#include <iostream> 

struct B 
{ 
    B(){ std::cout << "B()" << std::endl; } 
    ~B(){ std::cout << "~B()" << std::endl; } 
}; 

struct A 
{ 
    B b; 
    A(){ std::cout << "A()" << std::endl; throw std::exception(); } 
    ~A(){ std::cout << "~A()" << std::endl; } 
}; 

int main() 
{ 
    A a; 
} 

il desctructor non è stato chiamato per netither AB. L'uscita effettiva:

B() 
A() 
terminate called after throwing an instance of 'std::exception' 
    what(): std::exception 
bash: line 7: 21835 Aborted     (core dumped) ./a.out 

http://coliru.stacked-crooked.com/a/9658b14c73253700

Quindi qualsiasi momento il costruttore lancia durante l'inizializzazione delle variabili di blocco scope, otteniamo UB?

+2

Hai lanciato un'eccezione e non l'hai catturato, quindi il programma è stato interrotto. Cosa ti fa pensare che sia UB? – Beta

risposta

15

No, lanciare un'eccezione è il modo migliore per segnalare un errore durante la costruzione dell'oggetto. (. Dal momento che non c'è alcun valore di ritorno, non c'è altro modo, diverso la costruzione di un oggetto senza testa, che è cattivo stile in C++)

Da l'uomo stesso, Bjarne Stroustrup: http://www.stroustrup.com/bs_faq2.html#ctor-exceptions

Re: "Ma il mio distruttore non è stato chiamato "

Infatti. In C++ si dice che la durata di un oggetto inizia quando il costruttore esegue il completamento. E finisce proprio quando viene chiamato il distruttore. Se il ctor lancia, il dtor non viene chiamato.

(Ma dtors di eventuali oggetti variabili membro, la cui ctors già corse fino al completamento prima questo Ran ctor, sono chiamati.)

Si consiglia di consultare la norma, o di un libro di testo buona per maggiori dettagli, esp. in relazione a ciò che accade quando è coinvolta l'ereditarietà. Come regola generale, i distruttori sono chiamati nell'ordine inverso di costruzione.

La tua domanda sul motivo per cui "~ B" non è stato chiamato nel codice specifico, è perché non si cattura l'eccezione in main. Se cambi il tuo codice in modo che il principale rilevi l'eccezione, verrà chiamato "~ B()". Ma quando viene lanciata un'eccezione che non ha catture, l'implementazione è libera di terminare il programma senza chiamare distruttori o distruggere oggetti inizializzati staticamente.

riferimento a 11 C++ standard (sottolineatura mia):

15.5.1 La std :: terminate() funzione [except.terminate]

In alcuni le situazioni che gestiscono le eccezioni devono essere abbandonate per tecniche di gestione degli errori meno sottili.

...

In questi casi, std :: terminate() è chiamato (18.8.3). Nella situazione in cui non viene trovato alcun gestore corrispondente, viene definita l'implementazione indipendentemente dal fatto che lo stack venga svolto prima che std :: terminate() venga chiamato.

+0

Ma il distruttore non è stato chiamato per l'oggetto costruttore (B b) ... – stella

+0

__Si dovrebbe consultare lo standard, o un buon libro di testo per maggiori dettagli .__ Ho fatto 6.7/4, l'unico che ho trovato è questo: __Se il l'inizializzazione termina lanciando un'eccezione, l'inizializzazione non è completa, quindi verrà tentata di nuovo la volta successiva che il controllo immette la dichiarazione .__ – stella

+0

Cercherò di trovare ora un riferimento per quanto riguarda l'implementazione essere liberi di non distruggere le cose quando un'eccezione non rilevata si verifica –

3

L'eccezione di lancio nel costruttore è un modo standard di gestione degli errori e non è un comportamento indefinito. Se si lancia il costruttore, si presume che un oggetto non sia stato inizializzato correttamente, quindi il suo distruttore non viene chiamato.

+1

Ma il' B b' era. Quindi, dovrebbe essere distruttore, giusto? – stella

Problemi correlati