Ausnahmen: Änderungen für Ausnahmemakros in Version 3.0
Dies ist ein erweitertes Thema.
In MFC, Version 3.0 und höher, wurden die Ausnahmebehandlungsmakros geändert, um C++-Ausnahmen zu verwenden. In diesem Artikel wird erläutert, wie sich diese Änderungen auf das Verhalten von vorhandenem Code auswirken können, der die Makros verwendet.
In diesem Artikel werden die folgenden Themen behandelt:
Ausnahmetypen und das CATCH-Makro
In früheren Versionen von MFC verwendete das CATCH-Makro MFC-Laufzeittypinformationen, um den Typ einer Ausnahme zu ermitteln. Der Typ der Ausnahme wird also an der Catch-Site bestimmt. Bei C++-Ausnahmen wird der Typ der Ausnahme jedoch immer auf der Auslösenwebsite durch den Typ des ausgelösten Ausnahmeobjekts bestimmt. Dies führt zu Inkompatibilitäten in dem seltenen Fall, in dem sich der Zeigertyp auf das ausgelöste Objekt vom Typ des ausgelösten Objekts unterscheidet.
Im folgenden Beispiel wird die Folge dieses Unterschieds zwischen MFC Version 3.0 und früheren Versionen veranschaulicht:
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
Dieser Code verhält sich in Version 3.0 anders, da das Steuerelement immer mit einer übereinstimmenden Ausnahmedeklaration an den ersten catch
Block übergibt. Das Ergebnis des Auslösenausdrucks
THROW((CException*) new CCustomException());
wird als ein CException*
geworfen, obwohl es als ein CCustomException
. Das CATCH-Makro in MFC-Versionen 2.5 und früher verwendet CObject::IsKindOf
, um den Typ zur Laufzeit zu testen. Da der Ausdruck
e->IsKindOf(RUNTIME_CLASS(CException));
ist wahr, der erste Catch-Block fängt die Ausnahme ab. In Version 3.0, die C++-Ausnahmen verwendet, um viele der Ausnahmebehandlungsmakros zu implementieren, entspricht der zweite Catch-Block dem ausgelösten CException
.
Code wie dies ist ungewöhnlich. Es wird in der Regel angezeigt, wenn ein Ausnahmeobjekt an eine andere Funktion übergeben wird, die eine generische CException*
Funktion akzeptiert, die Verarbeitung vor dem Auslösen durchführt und schließlich die Ausnahme auslöst.
Um dieses Problem zu umgehen, verschieben Sie den Auslösenausdruck von der Funktion in den aufrufenden Code, und lösen Sie eine Ausnahme des tatsächlichen Typs aus, der dem Compiler zum Zeitpunkt der Erstellung der Ausnahme bekannt ist.
Erneutes Auslösen von Ausnahmen
Ein Catch-Block kann nicht denselben Ausnahmezeiger auslösen, den er abgefangen hat.
Dieser Code war beispielsweise in früheren Versionen gültig, hat aber unerwartete Ergebnisse mit Version 3.0:
TRY
{
// Do something to throw an exception.
AfxThrowUserException();
}
CATCH(CException, e)
{
THROW(e); // Wrong. Use THROW_LAST() instead
}
END_CATCH
}
Die Verwendung von THROW im Catch-Block bewirkt, dass der Zeiger e
gelöscht wird, sodass die äußere Fangwebsite einen ungültigen Zeiger empfängt. Verwenden Sie THROW_LAST , um es erneut auszuwerfen e
.
Weitere Informationen finden Sie unter Ausnahmen: Abfangen und Löschen von Ausnahmen.