2015-08-20 8 views
6

Sto scrivendo un drop-replacement per un container, e sto cercando di ottenere tutte le garanzie di eccezione sul posto. Al momento sto scrivendo il metodo clear e voglio completarlo il più possibile, e lasciare sempre il contenitore in uno stato coerente, anche se uno dei distruttori genera un'eccezione. Voglio anche riproporre l'eccezione dopo che ho finito di pulire, preferibilmente senza affettare.Quando un oggetto di eccezione viene distrutto (e può essere controllato)?

Questo mi porta alla domanda; quando viene distrutta un'eccezione? Diamo un'occhiata a un tentativo: Questo è semplificato per l'esempio.

void container::clear() 
{ 
    bool had_exception = false; 
    std::exception* exp; 
    internal_set_empty(); // this cant throw 
    while(! internal_done()) 
    { 
     try 
     { 
      internal_destruct_next(); // this might throw if T::~T() throws 
     } 
     catch(std::exception& e) 
     { 
      had_exception = true; 
      exp = &e; 
     } 
    } 
    if(had_exception) 
     throw *exp; 
} 

mi aspetto che questo mal di fallire, perché l'eccezione è probabilmente distrutto se si considera manipolati, e questo non tecnicamente rethrow.

Un altro tentativo sarebbe quello di prendere una copia dell'eccezione, qualcosa che mi aspetterebbe di affettare.

C'è un modo per estendere la durata dell'eccezione in modo da poter ripensare a in seguito? Se possibile, vorrei anche essere in grado di rilanciare le eccezioni rilevate tramite catch(...).

+0

http: // en.cppreference.com/w/cpp/error/exception_ptr potrebbe essere utile se lo scenario può funzionare. – Mat

+0

@Mat 'exception_ptr' sembra esattamente quello che stavo cercando, ma sembra che ci sia un problema più fondamentale. – sp2danny

risposta

4

anche se uno dei distruttori gettare un'eccezione

non può essere fatto. I distruttori sono sparpagliati per un motivo - non puoi recuperare da un distruttore di lancio. È chiaro che non fai nulla per ripulire gli oggetti il ​​cui distruttore ha gettato - perché potresti anche provare a farlo - ma questo significa anche che li hai appena lasciati in uno stato di zombi.

Sulla tua domanda più specifica, è possibile utilizzare la ricorsione per rimanere all'interno dello stack frame del catch per provare a eliminare gli elementi, oppure è possibile utilizzare std::exception_ptr e gli amici in C++ 11 che sono destinati al trasporto di eccezioni.

+0

Grazie. Ho anche trovato [questo] (http://stackoverflow.com/questions/130117/throwing-exceptions-out-of-a-distructor) per essere interessante – sp2danny

1

L'utilizzo corrente per passare l'eccezione a un chiamante consiste nel ricollocarlo nel blocco catch. Supponendo che abbiate buoni motivi per non farlo, l'unico altro modo corretto è usare uno std::exception_ptr. Con un semplice std::exception* ci sono alti rischi che l'eccezione venga distrutta e la sua memoria venga deallocata prima che tu possa lanciarla di nuovo.

standard C++ 2011 Progetto (n4296) dice a 15.1 Lanciare una § un'eccezione 4: L'eccezione oggetto viene distrutto dopo sia l'ultima rimanente gestore attivo per le uscite di eccezione con qualsiasi mezzo altri di rethrowing, o l'ultimo oggetto di tipo std :: exception_ptr che fa riferimento all'oggetto di eccezione è distrutto, a seconda di quale dei due è successivo. Nel primo caso, la distruzione si verifica quando il gestore esce, immediatamente dopo la distruzione dell'oggetto, se presente, nella dichiarazione di eccezione nel gestore. Nell'ultimo caso , la distruzione avviene prima che il distruttore di std :: exception_ptr ritorni. L'implementazione può quindi deallocare la memoria per l'oggetto di eccezione; qualsiasi tale deallocazione viene effettuata in un modo non specificato (enfatizza il mio)

Problemi correlati