Eccezioni: modifiche alle macro eccezioni nella versione 3.0
Si tratta di un argomento avanzato.
Nelle versioni di MFC 3,0 e versioni successive, le macro di gestione delle eccezioni sono state modificate per utilizzare le eccezioni C++. Questo articolo descrive come tali modifiche possono influire sul comportamento del codice esistente che utilizza le macro.
Questo articolo tratta i seguenti argomenti:
Tipi di eccezione e la macro CATCH
Ri-generazione di eccezioni
Tipi di eccezione e la macro CATCH
Nelle versioni precedenti di MFC, la macro CATCH utilizza le informazioni sui tipi di runtime MFC per determinare il tipo di eccezioni; il tipo di eccezioni è determinato, ovvero al sito catch. Con le eccezioni C++, tuttavia, il tipo di eccezione sono sempre determinate al sito throw dal tipo dell'oggetto dell'eccezione generato. Ciò causerà incompatibilità nei rari casi in cui il tipo del puntatore all'oggetto generato è diverso dal tipo dell'oggetto generato.
Nell'esempio seguente viene illustrato il risultato di questa differenza tra la versione di MFC 3,0 e versioni precedenti:
TRY
{
THROW( (CException*) new CCustomException() );
}
CATCH( CCustomException, e )
{
TRACE( "MFC 2.x will land here\n" );
}
AND_CATCH( CException, e )
{
TRACE( "MFC 3.0 will land here\n" );
}
END_CATCH
Questo codice si comporta in modo diverso nella versione 3,0 perché il controllo passa sempre prima a Catch il blocco con una dichiarazione dell'eccezione corrispondente. Risultato dell'espressione lanciata
THROW( (CException*) new CCustomException() );
viene generato come CException*, anche se viene costruito come CCustomException. La macro CATCH in MFC versione 2.5 e precedente usa CObject::IsKindOf per verificare il tipo in fase di esecuzione. A causa dell'espressione
e->IsKindOf(RUNTIME_CLASS(CException));
è true, i primi blocchi catch catturano l'eccezione. Nella versione 3,0, che utilizza le eccezioni C++ per implementare molte delle macro di gestione delle eccezioni, il secondo blocco catch corrisponde l'eccezione CException.
Il codice di questo tipo è raro. In genere viene visualizzato quando un oggetto eccezione viene passato a un'altra funzione che accetta CException* generico, esegue l'elaborazione "pre-throw" e infine genera l'eccezione.
Per risolvere questo problema, spostare l'espressione throw dalla funzione nel codice chiamante e genera un'eccezione di tipo conosciuto dal compilatore quando viene generata un'eccezione.
Ri-generazione di eccezioni
Un blocco catch non può generare lo stesso puntatore di eccezione che ha intercettato.
Ad esempio, questo codice è valido nelle versioni precedenti, ma avrà risultati imprevisti con la versione 3.0:
TRY
{
// Do something to throw an exception.
AfxThrowUserException();
}
CATCH( CException, e )
{
THROW( e ); // Wrong. Use THROW_LAST() instead
}
END_CATCH
}
Utilizzando THROW nel blocco catch causa l'eliminazione del puntatore e in modo che il sito esterno catch riceverà un puntatore non valido. Utilizzare THROW_LAST per generare nuovamente e.
Per ulteriori informazioni, consultare Eccezioni: Rilevazione e l'eliminazione delle eccezioni.