2011-04-11 11 views
8

ho alcuni oggetti sullo stack in funzione principale:Termina applicazione e chiamare i distruttori di oggetti locali

int main(...) 
{ 
    CFoo foo; 
    CBar bar; 
} 

Inoltre, ho una funzione, che tiene traccia di errori nella mia domanda:

void Err(std::string msg) 
{ 
    SomehowLogErrorMessage(msg); 
    exit(1); 
} 

La funzione di errore è sicuramente utile quando devo segnalare un errore irreversibile. Ho appena registrato l'errore e terminato l'applicazione - non può recuperare dopo tali errori. Tuttavia, terminare con "exit()" non invoca foo e bar destructors - un comportamento, che in realtà mi aspettavo (ma era sbagliato). "abort()" non aiuta neanche. Inoltre, Non posso usare le eccezioni per catturarle in main(). C'è un altro modo per implementare la funzione Err in modo tale che termina l'app e pulisce correttamente gli oggetti stack? O dovrei in qualche modo ridisegnare la mia gestione degli errori?

Grazie!


p.s. A proposito, non posso inviare il messaggio WM_QUIT alla mia finestra principale? Non sto bene con WinAPI, ma la mia app è pura Win32 e la mia funzione Err() può ottenere un handle per la mia finestra principale. Funzionerà?

+2

Ovvio, domanda stupida, ma perché non è possibile utilizzare le eccezioni? – forsvarir

+0

Se non puoi lanciare un'eccezione (perché no?) L'altra opzione è quella di restituire un codice di errore, e poi propagarlo fino alla fine del main. –

+0

Diciamo, restrizioni specifiche della piattaforma. Il progetto è compilato con flag -fno-exceptions. – SadSido

risposta

3

Non senza eccezioni o di ritorno normalmente da Err fino in fondo al callstack. Hai bisogno di scaricare la pila.

0

Credo che Exit interromperà immediatamente l'applicazione. Per vedere il comportamento che si sta aspettando, foo e bar, si dovrebbe andare fuori campo. Ciò significa che la funzione principale dovrebbe terminare normalmente con un valore di ritorno. Invece di chiamare Exit() dalla funzione Err, è necessario trovare un modo per tornare alla funzione principale e lasciare che ritorni normalmente con un valore di errore.

2

C'è ancora C setjmp e longjmp. Dovrebbe riportarti a main, quindi il programma terminerebbe normalmente dopo aver lasciato l'ambito di main, nel qual caso il meccanismo di distruttore di C++ distruggerà gli oggetti locali in main.

Ovviamente l'uso di longjmp è corrugato in C++ per buone ragioni. Salterà qualsiasi altra funzione nello stack, quindi funziona solo per pochi oggetti stack in main.

Potrebbe essere più semplice allocare gli oggetti nello heap e manualmente in Err.

+0

E salta anche quelli tra Err e main (non nel requisito? :-) –

+0

Beh, sarebbe terribile, ma almeno ci porterebbe a Main() ... Vorrei davvero progettare la mia gestione degli errori se fossi l'OP piuttosto che hackerare. –

+0

Non penso che sia sicuro dire che una funzione runtime C chiamerà distruttori. Anche la pagina di manuale dice che il registro e le variabili automatiche avranno valori indefiniti. –

1

Esistono fondamentalmente due metodi per propagare gli errori in C++: eccezioni (che apparentemente sono state arbitrariamente escluse) e codici di ritorno.

Dal momento che non è possibile utilizzare le eccezioni, è necessario iniziare a passare i codici di ritorno dalle funzioni che potrebbero non riuscire e testarli per vedere se è necessario interrompere e tornare al principale. Se non si srotola lo stack in questo modo, non c'è modo di garantire che i distruttori vengano chiamati correttamente.

Considerate anche che se il vostro programma si trova in uno stato fatale, i distruttori saranno effettivamente in grado di effettuare una pulizia attenta? Cosa succede se lo stato dell'oggetto è difettoso e non può essere rimosso correttamente? Invece di chiamare exit, è possibile chiamare abort che lascerebbe almeno un core per diagnosticare il problema in caso di cattivo stato. Per errori fatali in cui le eccezioni non sono disponibili questa è una scelta ragionevole.

+0

Bene, il programma non è in stato fatale (niente è danneggiato). Ma il lavoro successivo è inutile, ecco perché stavo cercando un modo per uscire proprio qui e ora. E speravo di evitare un pacchetto di codice di non ritorno-controllo-propagazione non necessario ... – SadSido

+4

In altre parole, "Voglio esattamente quali eccezioni offrono, ma non posso usare eccezioni" – Novelocrat

+0

È esattamente ciò che io voglio – SadSido

0

Vorrei riprogettare la gestione degli errori. La cosa più semplice da fare è restituire il controllo a main e lasciare che esegua la normale pulizia. Le eccezioni forniscono questa capacità tramite lo sbobinamento dello stack, ma non è possibile utilizzare le eccezioni. Ok va bene. A volte non puoi semplicemente usare le eccezioni.

Quindi invece di avere Err provare a chiudere il programma, fare in modo che l'errore sia Err e restituire un codice di errore. Idealmente, Err non dovrebbe fare comunque due lavori, che si sta provando a farlo fare: 1) Registrare l'errore, 2) Terminare l'applicazione con garbo.

Se la tua applicazione sembra essere multithread, potresti avere un fail out facile. Nel thread di registrazione degli errori, segnalare un evento "die". Fai in modo che il thread principale attenda su questo evento insieme a qualsiasi altra cosa sia in attesa (o inietta un lavoro tramite lo QueueUserAPC o simile). Quando viene segnalato l'evento, chiudi l'app.

+0

Questo mi costringerebbe ad analizzare il codice di errore fino in cima allo stack delle chiamate. Questo è quello che stavo cercando di evitare, ora penso che sia impossibile per C++. Peggio ancora, Err() può essere chiamato all'interno del costruttore di oggetti - e come posso passare il codice di errore da lì? – SadSido

Problemi correlati