Eccezioni: rilascio di oggetti nelle eccezioni
Questo articolo illustra la necessità e il metodo di liberare oggetti quando si verifica un'eccezione. Gli argomenti includono:
Eccezioni generate dal framework o dal flusso normale del programma dell'applicazione. Pertanto, è molto importante tenere traccia degli oggetti in modo che sia possibile eliminarli correttamente nel caso in cui venga generata un'eccezione.
A tale scopo, sono disponibili due metodi principali.
Gestire le eccezioni in locale usando le
try
parole chiave ecatch
, quindi eliminare tutti gli oggetti con un'unica istruzione.Eliminare definitivamente qualsiasi oggetto nel
catch
blocco prima di generare l'eccezione all'esterno del blocco per un'ulteriore gestione.
Questi due approcci sono illustrati di seguito come soluzioni all'esempio problematico seguente:
void SomeFunc() // Problematic code
{
CPerson* myPerson = new CPerson;
// Do something that might throw an exception.
myPerson->SomeFunc();
// Now destroy the object before exiting.
// If SomeFunc above throws an exception this code will
// not be reached and myPerson will not be deleted.
delete myPerson;
}
Come scritto in precedenza, myPerson
non verrà eliminato se viene generata un'eccezione da SomeFunc
. L'esecuzione passa direttamente al gestore di eccezioni esterno successivo, ignorando la normale uscita dalla funzione e il codice che elimina l'oggetto. Il puntatore all'oggetto esce dall'ambito quando l'eccezione lascia la funzione e la memoria occupata dall'oggetto non verrà mai recuperata finché il programma è in esecuzione. Si tratta di una perdita di memoria; viene rilevato usando la diagnostica della memoria.
Gestione dell'eccezione in locale
Il paradigma try/catch fornisce un metodo di programmazione difensiva per evitare perdite di memoria e garantire che gli oggetti vengano eliminati definitivamente quando si verificano eccezioni. Ad esempio, l'esempio illustrato in precedenza in questo articolo può essere riscritto come segue:
void SomeFunc()
{
CPerson* myPerson = new CPerson;
try
{
// Do something that might throw an exception.
myPerson->SomeFunc();
}
catch (CException* e)
{
// Handle the exception locally
e->Delete();
}
// Now destroy the object before exiting.
delete myPerson;
}
Questo nuovo esempio configura un gestore eccezioni per rilevare l'eccezione e gestirla in locale. Esce quindi dalla funzione normalmente e distrugge l'oggetto. L'aspetto importante di questo esempio è che viene stabilito un contesto per intercettare l'eccezione con i blocchi try/catch . Senza un frame di eccezione locale, la funzione non saprebbe mai che un'eccezione era stata generata e non avrebbe la possibilità di uscire normalmente ed eliminare definitivamente l'oggetto.
Generazione di eccezioni dopo la distruzione di oggetti
Un altro modo per gestire le eccezioni consiste nel passarli al successivo contesto esterno di gestione delle eccezioni. catch
Nel blocco è possibile eseguire alcune operazioni di pulizia degli oggetti allocati in locale e quindi generare l'eccezione per un'ulteriore elaborazione.
La funzione di throwing può o non deve deallocare oggetti heap. Se la funzione dealloca sempre l'oggetto heap prima di restituire nel caso normale, la funzione deve deallocare anche l'oggetto heap prima di generare l'eccezione. D'altra parte, se la funzione in genere non dealloca l'oggetto prima di restituire nel caso normale, è necessario decidere in base a maiuscole e minuscole se l'oggetto heap deve essere deallocato.
Nell'esempio seguente viene illustrato come pulire gli oggetti allocati in locale:
void SomeFunc()
{
CPerson* myPerson = new CPerson;
try
{
// Do something that might throw an exception.
myPerson->SomeFunc();
}
catch (CException* e)
{
e->ReportError();
// Destroy the object before passing exception on.
delete myPerson;
// Throw the exception to the next handler.
throw;
}
// On normal exits, destroy the object.
delete myPerson;
}
Il meccanismo di eccezione dealloca automaticamente gli oggetti frame; viene chiamato anche il distruttore dell'oggetto frame.
Se si chiamano funzioni che possono generare eccezioni, è possibile usare blocchi try/catch per assicurarsi di intercettare le eccezioni e avere la possibilità di eliminare tutti gli oggetti creati. In particolare, tenere presente che molte funzioni MFC possono generare eccezioni.
Per altre informazioni, vedere Eccezioni: rilevamento ed eliminazione di eccezioni.