2013-03-09 8 views
6

Il C++ standard afferma quanto segue riguardo l'esecuzione di std::call_once con funzioni che gettano eccezioni (§30.4.4.2/2):un'eccezione da std :: call_once

2/Effetti: Un'esecuzione di call_once ciò non chiama la sua funzione è un'esecuzione passiva. Un'esecuzione di call_once che chiama la sua funzione è un'esecuzione attiva. Un'esecuzione attiva deve chiamare INVOKE (DECAY_- COPY (std :: forward (func)), DECAY_COPY (std :: forward (args)) ...). Se tale chiamata a func genera un'eccezione, l'esecuzione è eccezionale, altrimenti viene restituita. Un'eccezionale esecuzione deve propagare l'eccezione al chiamante di call_once. Tra tutte le esecuzioni di call_once per ogni dato once_flag: al massimo una sarà un'esecuzione di ritorno; se c'è un'esecuzione di ritorno, deve essere l'ultima esecuzione attiva; e ci sono esecuzioni passive solo se c'è un'esecuzione di ritorno. [Nota: le esecuzioni passive consentono ad altri thread di osservare in modo affidabile i risultati prodotti dall'esecuzione di ritorno precedente. - nota end]

Sto utilizzando Visual Studio 2012 e l'esecuzione del seguente codice:

void f(){ 
    throw std::exception("Catch me!"); 
} 

int main(int argc, char* argv[]){ 
    once_flag flag; 
    try{ 
     call_once(flag, f); 
    } catch(const std::exception& e){ 
     cout << e.what() << endl; 
    } 
    return 0; 
} 

Il mio risultato è: il codice viene eseguito blocco catch e stampa il messaggio, ma quando il programma esisto ricevo una chiamata al abort() e il seguente messaggio stampato a cout:

... \ mutex.c (38) mutex distrutto mentre occupato

È questo dovrebbe succedere?

+2

No, è un bug, il programma dovrebbe funzionare bene (anche se stai usando un costruttore non standard per 'std :: exception', in ISO C++ puoi solo costruire predefinito' std :: exception', che causa frequenti problemi di portabilità quando gli utenti di MSVC controllano l'incodifica che si intende compilare su altre implementazioni) –

risposta

7

È possibile che ciò accada?

No, non proprio. Questo è un bug .

Tuttavia, notare il fatto che VC11 non è solo su questo:

  • Intel ICC 13.0.1 chiama std::terminate() come se la vostra eccezione non è stata gestita (vedi live example);
  • GCC 4.8.0 beta probabilmente fa qualcosa di simile, ma non mostra alcun output, semplicemente ingoia l'eccezione e termina silenziosamente il programma (vedere live example). [UPDATE: Questo bug non sembra essere riproducibile in altri ambienti ed è probabile che sia un problema con la configurazione sul liveworkspace.org solo]

GCC 4.7.2 e 3.2 Clang, d'altra parte , comportarsi correttamente

A proposito, vale la pena notare che lo standard C++ (paragrafo 18.8.1) specifica che std::exceptiononly has a default constructor and a copy constructor. Il costruttore che si sta utilizzando è molto probabilmente un'estensione MS non portatile.

È possibile utilizzare invece std::logic_error, che deriva da std::exception e supporta un costruttore che accetta una stringa.

+1

Grazie, non ero a conoscenza di std :: l'eccezione ha solo un costruttore predefinito e di copia, in realtà sto usando eccezioni personalizzate nel codice originale. Mi asterrò dal lanciare eccezioni da call_once per ora, grazie per i chiarimenti. –

+4

Vale anche la pena notare quando 'call_once' ritorna con un'eccezione, non è considerato soddisfatto. Cioè la prossima volta che viene eseguito 'call_once',' f' sarà tentato di nuovo. E così via, finché 'f' non ritorna senza fare un'eccezione. –

+0

@HowardHinnant: buona osservazione, grazie per averlo menzionato. –

Problemi correlati