Исключения. Изменения макроса исключений в версии 3.0
Это расширенный раздел.
В MFC версии 3.0 и более поздних версиях макросы обработки исключений были изменены на использование исключений C++. В этой статье описывается, как эти изменения могут повлиять на поведение существующего кода, использующего макросы.
В этой статье рассматриваются следующие темы:
Типы исключений и макрос CATCH
В более ранних версиях MFC макрос CATCH использовал сведения о типе времени выполнения MFC для определения типа исключения; тип исключения определяется, другими словами, на сайте catch. Однако при исключении C++ тип исключения всегда определяется на сайте броска по типу создаваемого объекта исключения. Это приведет к несовместимости в редких случаях, когда тип указателя на создаваемый объект отличается от типа вызываемого объекта.
В следующем примере показана разница между MFC версии 3.0 и более ранними версиями:
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
Этот код работает по-разному в версии 3.0, так как элемент управления всегда передается в первый catch
блок с соответствующим объявлением исключения. Результат выражения броска
THROW((CException*) new CCustomException());
создается как объектCException*
, несмотря на то, что он построен как .CCustomException
Макрос CATCH в MFC версии 2.5 и более ранних используется CObject::IsKindOf
для тестирования типа во время выполнения. Так как выражение
e->IsKindOf(RUNTIME_CLASS(CException));
имеет значение true, первый блок catch перехватывает исключение. В версии 3.0, которая использует исключения C++ для реализации многих макросов обработки исключений, второй блок catch соответствует создаваемому.CException
Код, подобный этому, является редким. Обычно возникает, когда объект исключения передается другой функции, которая принимает универсальную CException*
обработку, выполняет обработку перед вызовом и, наконец, создает исключение.
Чтобы обойти эту проблему, переместите выражение броска из функции в вызывающий код и создайте исключение фактического типа, известного компилятору во время создания исключения.
Повторное создание исключений
Блок catch не может вызвать тот же указатель исключения, который он поймал.
Например, этот код действителен в предыдущих версиях, но будет иметь непредвиденные результаты с версией 3.0:
TRY
{
// Do something to throw an exception.
AfxThrowUserException();
}
CATCH(CException, e)
{
THROW(e); // Wrong. Use THROW_LAST() instead
}
END_CATCH
}
Использование THROW в блоке catch приводит к удалению указателя e
, чтобы внешний сайт catch получил недопустимый указатель. Используйте THROW_LAST для повторного создания e
.
Дополнительные сведения см. в разделе "Исключения: перехват и удаление исключений".