Wyjątki: zmiany w makrach wyjątków w wersji 3.0
Jest to zaawansowany temat.
W MFC w wersji 3.0 lub nowszej makra obsługi wyjątków zostały zmienione w celu używania wyjątków języka C++. W tym artykule opisano, jak te zmiany mogą mieć wpływ na zachowanie istniejącego kodu korzystającego z makr.
W tym artykule opisano następujące tematy:
Typy wyjątków i makro CATCH
We wcześniejszych wersjach MFC makro CATCH używało informacji o typie czasu wykonywania MFC w celu określenia typu wyjątku; typ wyjątku jest określany, innymi słowy, w miejscu przechwytywania. Jednak w przypadku wyjątków języka C++ typ wyjątku jest zawsze określany w lokacji zgłaszanej przez typ zgłoszonego obiektu wyjątku. Spowoduje to niezgodności w rzadkich przypadkach, w których typ wskaźnika do obiektu rzuconego różni się od typu zgłaszanego obiektu.
Poniższy przykład ilustruje konsekwencję tej różnicy między MFC w wersji 3.0 i starszych wersji:
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
Ten kod działa inaczej w wersji 3.0, ponieważ kontrolka zawsze przechodzi do pierwszego catch
bloku z zgodną deklaracją wyjątku. Wynik wyrażenia throw
THROW((CException*) new CCustomException());
element jest zgłaszany jako element CException*
, mimo że jest on skonstruowany jako CCustomException
. Makro CATCH w MFC w wersji 2.5 i starszych używa CObject::IsKindOf
do testowania typu w czasie wykonywania. Ponieważ wyrażenie
e->IsKindOf(RUNTIME_CLASS(CException));
to prawda, pierwszy blok catch przechwytuje wyjątek. W wersji 3.0, która używa wyjątków języka C++, aby zaimplementować wiele makr obsługi wyjątków, drugi blok catch jest zgodny z zgłoszonym CException
.
Kod podobny do tego jest nietypowy. Zwykle pojawia się, gdy obiekt wyjątku jest przekazywany do innej funkcji, która akceptuje ogólny CException*
, wykonuje przetwarzanie "przedrzucanie", a na koniec zgłasza wyjątek.
Aby obejść ten problem, przenieś wyrażenie throw z funkcji do kodu wywołującego i zgłoś wyjątek rzeczywistego typu znanego kompilatorowi w momencie wygenerowania wyjątku.
Ponowne zgłaszanie wyjątków
Blok catch nie może zgłosić tego samego wskaźnika wyjątku, który został przechwycony.
Na przykład ten kod był prawidłowy w poprzednich wersjach, ale będzie miał nieoczekiwane wyniki z wersją 3.0:
TRY
{
// Do something to throw an exception.
AfxThrowUserException();
}
CATCH(CException, e)
{
THROW(e); // Wrong. Use THROW_LAST() instead
}
END_CATCH
}
Użycie funkcji THROW w bloku catch powoduje usunięcie wskaźnika e
, dzięki czemu zewnętrzna lokacja przechwytywania otrzyma nieprawidłowy wskaźnik. Użyj THROW_LAST , aby ponownie zgłosić element e
.
Aby uzyskać więcej informacji, zobacz Wyjątki: przechwytywanie i usuwanie wyjątków.