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


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

если истинно, первый блок catch перехватывает исключение. В версии 3.0, которая использует исключения C++ для реализации многих макросов обработки исключений, второй блок catch соответствует выброшенному CException.

Код, подобный этому, является редким. Обычно возникает, когда объект исключения передается другой функции, которая принимает его как универсальный CException*, выполняет обработку перед выбрасыванием и, наконец, выбрасывает исключение.

Чтобы обойти эту проблему, переместите выражение броска из функции в вызывающий код и создайте исключение фактического типа, известного компилятору во время создания исключения.

Re-Throwing Исключения

Блок 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.

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

См. также

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