Я проводил некоторые эксперименты с SEH. В своем коде я написал блок, вызывающий ошибку, в предложении __try и обработчик в __except ().
__try{
Test *pTest = 0;
int k = pTest->GetValue();
cout << "continue after exception" << endl;
}
__except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION,EXCEPTION_EXECUTE_HANDLER)
{
cout << "caught!!" << endl;
}
cout << "Exception handled" << endl;
Второй параметр __except () является одним из следующих:
EXCEPTION_CONTINUE_SEARCH Исключение не распознано. Продолжайте искать в стеке обработчик, сначала содержащий операторы try-кроме, затем обработчики со следующим наивысшим приоритетом.
EXCEPTION_CONTINUE_EXECUTION Исключение распознается, но отклоняется. Продолжите выполнение в том месте, где произошло исключение.
EXCEPTION_EXECUTE_HANDLER Исключение распознано. Передайте управление обработчику исключений, выполнив составной оператор __except, затем продолжите выполнение в том месте, где произошло исключение.
Когда я использую EXCEPTION_CONTINUE_EXECUTION / EXCEPTION_EXECUTE_HANDLER, он не продолжает выполнение в точке возникновения исключения (возможно, я неверно истолковываю значение точки возникновения исключения).
Когда я запускаю его в режиме отладки, вывод
caught
Exception handled
Когда я запускаю его в режиме выпуска, вывод
continue after exception
Exception handled
Я не мог понять, почему он ведет себя по-другому. Кто-нибудь, пожалуйста, помогите.
@Joachim правильно указывает на проблему оператора запятой.
Я думаю __except()
должен выглядеть так:
__except((GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ?
EXCEPTION_EXECUTE_HANDLER :
EXCEPTION_CONTINUE_SEARCH)
Это заставит обработчик исключения выполняться, если исключение является нарушением прав доступа. Если это не так, исключение будет распространяться до ближайшего внешнего __try
если есть.
Я боюсь что pTest
является указателем на класс, и для его выполнения может не потребоваться разыменование GetValue()
и компилятор распознает это, когда оптимизации включены в режиме выпуска. Или, может быть, даже это видит GetValue()
как бесполезный и не генерирует никакого кода для его вызова. Также возможно, что компилятор видит, что разыменование NULL-указателя приводит к неопределенному поведению, и решает наказать вас за это во время компиляции, испортив ваш код, он имеет полное право сделать это. например, gcc печально известен этим.
Выражение
GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION,EXCEPTION_EXECUTE_HANDLER
не делает то, что вы ожидаете. Что это делает, это сравнить результат GetExceptionCode()
с EXCEPTION_ACCESS_VIOLATION
, но результат всего выражения EXCEPTION_EXECUTE_HANDLER
,
Подробнее о запятом в Википедии.
Что вы хотите сделать, это, вероятно,
GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION || GetExceptionCode() == EXCEPTION_EXECUTE_HANDLER