Procedura: Progettazione di sicurezza di eccezione
Uno dei vantaggi del meccanismo di eccezione è che l'esecuzione, insieme ai dati sull'eccezione, passare direttamente dall'istruzione che genera l'eccezione alla prima istruzione catch che gestisce.Il gestore può essere un numero qualsiasi di livelli nello stack di chiamate.Le funzioni definite tra l'istruzione try e l'istruzione throw non sono necessarie per conoscenza l'una dell'eccezione generata.Tuttavia, devono essere progettate in modo da poter chiudere di ambito "imprevista" in qualsiasi punto in cui un'eccezione può propagarsi in da in e agiscono in modo che senza passare agli oggetti, la memoria persa, o strutture di dati parzialmente creata presenti negli stati inutilizzabili.
Tecniche base
I criteri efficaci di gestione delle eccezioni richiedono una considerazione avviso e devono far parte del processo di progettazione.Nella maggior parte delle eccezioni vengono rilevate e generate ai livelli inferiori di un modulo del software, ma in genere questi livelli non dispongono di contesto sufficiente per gestire l'errore o per esporre un messaggio agli utenti finali.Nel livello intermedio, le funzioni possono rilevare e generare un'eccezione quando è necessario controllare l'oggetto eccezione, o di informazioni utili aggiuntive da fornire al livello superiore che a intercetta l'eccezione.Una funzione dovrebbe intercettare e "inghiottire" un'eccezione solo se è completamente da recuperare da.In molti casi, il comportamento corretto nel livello intermedio consiste nel consentire alla propagazione delle eccezioni nello stack di chiamate.Anche al livello superiore, potrebbe essere opportuno lasciare un'eccezione non gestita terminare un programma se l'eccezione consente al programma in uno stato in cui la precisione non può essere garantita.
Indipendentemente da come una funzione gestisce un'eccezione, per garantire che è "indipendente dalle eccezioni," deve essere progettata in base alle seguenti regole di base.
Mantenere le classi di risorse semplici
Quando incapsulate la gestione delle risorse manuale nelle classi, una classe di utilizzo che esegue l'ancoraggio gestire ogni risorsa; in caso contrario, potrebbe provocare perdite.
Utilizzare il linguaggio RAII per gestire le risorse
Per essere eseguita correttamente indipendentemente dalle eccezioni, una funzione deve garantire che gli oggetti che ha allocato utilizzando malloc o new si distruggano e le risorse come un handle di file sono chiuse o eliminate anche se viene generata un'eccezione.L'Acquisizione di risorse è inizializzazione gestione dei collegamenti di linguaggio di (RAII) di tali risorse alla durata delle variabili automatiche.Quando una funzione area di validità, restituendo in genere o a causa di un'eccezione, i distruttori per tutte le variabili automatiche completamente costruite vengono richiamati.Un oggetto wrapper RAII come un puntatore intelligente chiama la funzione appropriata di fine o di eliminazione nel distruttore.Nel codice indipendente dalle eccezioni, è estremamente importante passare la proprietà di ogni risorsa immediatamente a un tipo di oggetto RAII.Si noti che vector, string, make_shared, fstreame simili classi gestiscono l'acquisizione della risorsa automaticamente. Tuttavia, unique_ptr e le costruzioni tradizionali di shared_ptr sono speciali perché l'acquisizione di risorse viene eseguita dall'utente anziché oggetto; pertanto, vengono considerate come la versione di risorse è l'eliminazione ma sono incerti come RAII.
Le tre garanzie di eccezione
In genere, la sicurezza dell'eccezione viene discussa in termini di tre garanzie di eccezione che una funzione può fornire: garantire privi di errore, la garanzia fortee la garanzia di base.
Garanzia privi di errore
Garantire privi di errore, o "NO primary throw") è più sicuro garanzia che una funzione può fornire.Dichiara che la funzione non genererà un'eccezione o non consentirà una alla propagazione.Tuttavia, non è possibile in modo affidabile fornire tale garanzia a meno che () sapere che tutte le funzioni che questo le chiamate di funzione sono privi errore, o (b) per indicare che tutte le eccezioni generate vengono intercettate prima che vengano inviati a questa funzione, o (c) sapere intercettare e gestire correttamente le eccezioni che potrebbero ottenere la funzione.
Sia la forte garanzia che la garanzia di base si basano su presupposti che i distruttori sono privi errore.Tutti i contenitori e nella seconda standard di libreria che i distruttori non generano.Esiste anche un requisito inverso: La libreria standard è necessario che i tipi definiti dall'utente vengono forniti (ad esempio, come il modello argomento- deve essere non generare i distruttori.
Forte garanzia
Gli stati di garanzia che se una funzione area di validità a causa di un'eccezione, non coleranno lo stato del programma e di memoria non verranno modificati.Una funzione che fornisce una stretta garanzia è essenzialmente una transazione che presenta la semantica di rollback o di commit: o completamente avviata correttamente o non ha effetto.
Garanzia di base
La garanzia di base è il più debole i tre.Tuttavia, potrebbe essere la scelta migliore quando una stretta garanzia è troppo dispendiosa nel consumo di memoria o le prestazioni.Stati di base per garantire che se si verifica un'eccezione, non si verifichino perdite di memoria e l'oggetto è ancora in uno stato utilizzato anche se i dati possono essere modificati.
Classi eccezioni sicure
La classe può garantire la propria sicurezza dell'eccezione, anche quando viene utilizzata dalle funzioni pericolose, impedendosi parzialmente di essere costruita o parzialmente eliminato.Se il costruttore di classe prima del completamento, quindi l'oggetto non viene creata mai e il relativo distruttore non verrà mai chiamato.Sebbene le variabili automatiche che vengono inizializzati prima dell'eccezione non dispongano distruttori richiamati dinamicamente, la memoria allocata o le risorse che non sono gestiti da un puntatore intelligente o da una simile variabile automatica verrà cast.
I tipi incorporati sono qualsiasi privi errore e i tipi di librerie standard supportano la garanzia base al minimo.Seguire le linee guida per qualsiasi tipo definito dall'utente che deve essere indipendente dalle eccezioni:
Utilizzare i puntatori intelligenti o altri wrapper di RAII- tipo per gestire tutte le risorse.Evitare la funzionalità di gestione delle risorse nel distruttore di classe, perché il distruttore non verrà richiamato se il costruttore genera un'eccezione.Tuttavia, se la classe è un gestore di risorse dedicato che controlla solo una risorsa, è possibile utilizzare il distruttore per gestire le risorse.
Individuare di un'eccezione generata in un costruttore di classe base non può essere inghiottita in un costruttore di classe derivata.Se si desidera convertire e rigenerare l'eccezione della classe base in un costruttore derivato, utilizzare un blocco try di funzione.Per ulteriori informazioni, vedere Procedura: Le eccezioni nei costruttori della classe base (C++).
Considerare se l'adattatore archiviare uno stato della classe in un membro dati che viene eseguito il wrapping in un puntatore intelligente, specialmente se la classe dispone di un concetto di inizializzazione consentita per errore." Sebbene il linguaggio C++ lasciare spazio ai membri dati non inizializzata, non supporta le istanze della classe non inizializzate o parzialmente inizializzata.Un costruttore deve avere esito positivo o negativo; nessun oggetto viene creata se il costruttore non viene completata.
Non consentire alcune eccezioni in attesa di un distruttore.Un assioma di base C++ è che i distruttori non devono consentire mai un'eccezione che si propaghi nello stack di chiamate.Se un distruttore deve eseguire potenzialmente generare eccezioni l'operazione, deve farlo in un blocco try-catch e inghiottire l'eccezione.La libreria standard fornisce la garanzia su tutti i distruttori che definisce.
Vedere anche
Concetti
Errori e gestione delle eccezioni C++ (moderno)
Procedura: Interfaccia tra il codice eccezionale e Non Eccezionale