2012-10-04 18 views
6

Eventuali duplicati:
How to clean initialized resources if exception thrown from constructor in c++Come gestisco correttamente le eccezioni nei costruttori?

Come faccio a gestire un'eccezione nei costruttori se io sono la creazione di 6 oggetti e quegli oggetti creo 5 oggetto e non riesce durante la creazione del 6 ° uno?

Grazie.

+3

Che ne dici di link, che Als ti offre qui http://stackoverflow.com/questions/12723492/how-to-clean-initialized-resources-if-exception-thrown-from-constructor-in-c? Sono oggetti membri di questo membro? – ForEveR

+0

Quale maneggiamento avete bisogno? Normalmente, si dovrebbe semplicemente propagare l'eccezione, in modo che i primi 5 oggetti vengano distrutti in modo pulito. Qualche altro contesto sarebbe utile – jalf

+0

RAII. (Http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization) – ScaryAardvark

risposta

1

Quando viene generata un'eccezione nel costruttore, tutti gli oggetti secondari completamente costruiti vengono distrutti. Poiché è buona pratica che i distruttori di oggetti costruiti si occupino delle loro risorse, non è necessario fare nulla per questi sottooggetti. Ciò che rimane è la pulizia nel corpo del costruttore attualmente in esecuzione quando viene lanciata l'eccezione. Tuttavia, questo non è diverso dal clean-up in qualsiasi altra funzione.

Si noti che l'ordine di distruzione è il rovescio della costruzione. Cioè, la pulizia del corpo inizia prima quando tutti i sottooggetti non sono, ancora, distrutti. Quindi i membri vengono distrutti, quindi le classi base non virtuali e infine le classi base virtuali.

3

Il comportamento normale è quello di propagare l'eccezione. Distruttori per tutte le classi base costruite e i membri saranno chiamati; se i primi cinque oggetti sono membri, saranno corretti destrutturati.

L'unico caso in cui potrebbe verificarsi un problema è se gli oggetti che si sta parlando di sono stati allocati dinamicamente (utilizzando new). Se questo è il caso : la prima cosa da chiedersi è perché? Perché stai allocando dinamicamente e non rendi l'oggetto un membro concreto? Nell'esperienza , tale necessità è molto, molto rara, tranne in alcuni casi speciali (ad esempio l'idioma del firewall di compilazione), nel qual caso, ci sarà esattamente esattamente un oggetto nella classe (es. Un puntatore al oggetto di implementazione). In questi casi, non c'è alcun problema, perché se il new di quell'oggetto fallisce, non è stato fatto nient'altro che ha bisogno di annullare .

Se vi trovate nel caso eccezionalmente raro dove realmente è necessario utilizzare l'allocazione dinamica e avere più di un tale oggetto (ad esempio perché si dispone di due oggetti secondari quali sono polimorfi), poi si Dovremo assicurarci che ognuna delle allocazioni sia racchiusa in qualche tipo di sub-oggetto (un puntatore intelligente farà il trucco); una volta che il primo oggetto secondario è stato costruito con successo, il suo distruttore sarà chiamato se il costruttore fallisce in un secondo momento.

1

Al "nucleo" di gestione delle eccezioni è che praticamente tutto deve essere ripulito dai distruttori. Ad esempio, se "nuovo" un oggetto ottieni un puntatore "grezzo"; se viene lanciata un'eccezione devi assicurarti che questo puntatore raw sia correttamente "cancella" d - ma assicurati di non eliminare un puntatore raw che non è stato inizializzato.

D'altra parte, se si memorizza quel puntatore in uno std :: unique_ptr non è necessario fare nulla; quando il unique_ptr viene distrutto l'oggetto viene cancellato e la distruzione dell'oggetto avviene automaticamente: quando unique_ptr esce dall'ambito, il compilatore invoca la pulizia, completamente invisibile (quindi non più code-cluttering con tonnellate di chiamate di cleanup) e automaticamente (quindi non più 'ahi, quando prende quel percorso raro che nessuno ha veramente provato, dimentica di ripulire').

Lo stesso può essere applicato a quasi tutte le risorse; ci sono "puntatori automatici" per gli oggetti COM (come quelli usati in DirectX, per esempio), la maggior parte dei framework dovrebbe fornire un oggetto tipo "scope scope" per avvolgere mutex (quindi blocca il mutex quando l'oggetto viene creato, e lo sblocca quando è distrutto) e puoi scrivere minuscoli wrapper per gestire vari handle di Windows.

Fondamentalmente, se metti tutta la tua pulizia in distruttori, non dovrai mai "provare ... prendere ... ripensare" solo per ripulire. E i distruttori di oggetti "più grandi" saranno spesso molto semplici, poiché praticamente tutti gli oggetti "contenuti" vengono automaticamente rimossi dai loro distruttori.

Problemi correlati