Поделиться через


Исключения. Изменения макроса исключений в версии 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.

Дополнительные сведения см. в разделе "Исключения: перехват и удаление исключений".

См. также

Обработка исключений