In quali circostanze i distruttori C ++ non verranno chiamati?

So che i miei distruttori vengono chiamati al normale svolgimento dello stack e quando vengono lanciate eccezioni, ma non quando viene chiamato exit ().

Ci sono altri casi in cui i miei distruttori non verranno chiamati? Che dire dei segnali come SIGINT o SIGSEGV? Presumo che per SIGSEGV non vengano chiamati, ma per SIGNINT lo sono, come faccio a sapere quali segnali si srotoleranno?

Ci sono altre circostanze in cui non saranno chiamati?

Ci sono altre circostanze in cui [i distruttori] non saranno chiamati?

  1. Salti lunghi: interferiscono con il naturale processo di srotolamento dello stack e spesso portano a un comportamento indefinito in C ++.
  2. Uscite premature (le hai già segnalate, sebbene valga la pena notare che il lancio mentre si accumula già in fase di svolgimento come risultato di un’eccezione generata porta a comportamenti non definiti ed è per questo che non dovremmo mai abbandonare i dtors)
  3. Lanciare da un costruttore non invoca il dtor per una class. Questo è il motivo per cui, se si assegnano più blocchi di memoria gestiti da diversi puntatori (e non puntatori intelligenti) in un operatore, è necessario utilizzare blocchi di prova a livello di funzione o evitare l’utilizzo dell’elenco di inizializzazione e disporre di un blocco try / catch nel ctor body (o meglio ancora, basta usare un puntatore intelligente come scoped_ptr poiché qualsiasi membro inizializzato con successo fino ad ora in un elenco di inizializzazione sarà distrutto anche se il classdtor non verrà chiamato).
  4. Come sottolineato, non riuscire a creare un dtor virtuale quando una class viene cancellata tramite un puntatore di base potrebbe non riuscire a richiamare i drier della sottoclass (comportamento indefinito).
  5. Imansible chiamare l’operatore di corrispondenza delete / delete [] per un operatore new / new [] call (comportamento non definito – potrebbe non riuscire a richiamare dtor).
  6. Imansible richiamare manualmente il dtor quando si utilizza il nuovo posizionamento con un allocatore di memoria personalizzato nella sezione deallocate.
  7. Usando funzioni come memcpy che copia solo un blocco di memoria in un altro senza richiamare i coconi di copia. Le funzioni di mem * sono letali in C ++ in quanto eseguono il bulldozer sui dati privati ​​di una class, sovrascrivono i vtables, ecc. Il risultato è in genere un comportamento non definito.
  8. Istanziazione di alcuni dei puntatori intelligenti (auto_ptr) su un tipo incompleto, vedere questa discussione

Lo standard C ++ non dice nulla su come devono essere gestiti segnali specifici – molte implementazioni potrebbero non supportare SIGINT , ecc. I distruttori non verranno chiamati se vengono chiamati exit() o abort() o terminate() .

Edit: Ho appena avuto una rapida ricerca attraverso lo standard C ++ e non riesco a trovare nulla che specifica in che modo i segnali interagiscono con la vita degli oggetti – forse qualcuno con standard migliori – Fu di me potrebbe trovare qualcosa?

Ulteriore modifica: mentre rispondevo a un’altra domanda, ho trovato questo nello Standard:

All’uscita da un ambito (comunque compiuto), i distruttori (12.4) vengono chiamati per tutti gli oggetti costruiti con durata di archiviazione automatica (3.7.2) (oggetti o temporali denominati) dichiarati in tale ambito, nell’ordine inverso della loro dichiarazione.

Quindi sembra che i distruttori debbano essere chiamati al ricevimento di un segnale.

Un altro caso in cui non verranno chiamati è se si sta utilizzando il polimorfismo e non si sono resi virtuali i distruttori di base.

Un segnale di per sé non influirà sull’esecuzione del thread corrente e quindi sull’invocazione dei distruttori, poiché si tratta di un contesto di esecuzione diverso con un proprio stack, in cui i propri oggetti non esistono. È come un’interruzione: viene gestita da qualche parte al di fuori del contesto di esecuzione e, se gestita, il controllo viene restituito al programma.

Come con il multithreading, il linguaggio C ++ non conosce la nozione di segnali. Questi due sono completamente ortogonali tra loro e sono specificati da due standard non correlati. Il modo in cui interagiscono dipende dall’implementazione, a condizione che non infranga nessuno degli standard.

Come nota a margine, un altro caso è quando il distruttore dell’object non verrà chiamato quando il suo costruttore lancia un’eccezione. Tuttavia, i distruttori dei membri verranno comunque chiamati.

abort interrompe il programma senza eseguire i distruttori per oggetti di durata di archiviazione automatica o statica come dice Standard. Per altre situazioni, è necessario leggere i documenti specifici dell’implementazione.

Se una funzione o un metodo ha una specifica di tiri e getta qualcosa che NON è coperto dalle specifiche, il comportamento predefinito è di uscire immediatamente. Lo stack non viene svolto e i distruttori non vengono chiamati.

I segnali POSIX sono un costrutto specifico del sistema operativo e non hanno nozioni sull’ambito dell’object C ++. Generalmente non è ansible fare nulla con un segnale, ad eccezione forse di intercettarlo, impostare una variabile di flag globale e quindi gestirla in un secondo momento nel codice C ++ dopo che il gestore del segnale è uscito.

Le versioni recenti di GCC consentono di generare un’eccezione all’interno dei gestori di segnale sincrono, il che comporta il processo di svolgimento e distruzione previsto. Questo è molto specifico per il sistema operativo e il compilatore, comunque

Molte risposte qui ma ancora incomplete!

Ho trovato un altro caso in cui i distruttori non vengono eseguiti. Ciò accade sempre quando l’eccezione viene catturata attraverso il limite di una libreria.

Vedi maggiori dettagli qui:

I distruttori non vengono eseguiti (nessuno stack si svolge) quando viene lanciata un’eccezione

Ci sono fondamentalmente due situazioni, in cui i distruttori sono chiamati: On stack unwind alla fine della funzione (o alle eccezioni), se qualcuno (o un contatore di riferimento) chiama delete.

Una situazione speciale si trova negli oggetti statici: vengono distrutti alla fine del programma tramite at_exit, ma questa è ancora la seconda situazione.

Il segnale che lascia at_exit può dipendere, kill -9 ucciderà immediatamente il processo, altri segnali diranno di uscire ma quanto esattamente dipende dal callback del segnale.