Escrevendo um filtro de exceção
Você pode lidar com uma exceção indo diretamente ao nível do manipulador de exceção ou continuando a execução. Em vez de usar um código de manipulador de exceção para manipular a exceção e a queda, você pode usar um a expressão de filtro para limpar o problema. Em seguida, ao retornar EXCEPTION_CONTINUE_EXECUTION
(-1), você pode retomar o fluxo normal sem limpar a pilha.
Observação
Algumas exceções não podem ser retomadas. Se filter avalia uma exceção como -1, o sistema gera uma nova exceção. Ao chamar RaiseException
, você determina se uma exceção continuará.
Por exemplo, o código a seguir usa uma chamada de função na expressão filter: essa função manipula o problema e retorna -1 para retomar o fluxo de controle normal:
// exceptions_Writing_an_Exception_Filter.cpp
#include <windows.h>
int Eval_Exception(int);
int main() {
__try {
;
}
__except (Eval_Exception(GetExceptionCode())) {
;
}
}
void HandleOverflow() {
// Gracefully recover
}
int Eval_Exception(int n_except) {
if (
n_except != STATUS_INTEGER_OVERFLOW &&
n_except != STATUS_FLOAT_OVERFLOW
) {
// Pass on most exceptions
return EXCEPTION_CONTINUE_SEARCH;
}
// Execute some code to clean up problem
HandleOverflow();
return EXCEPTION_CONTINUE_EXECUTION;
}
Essa é uma boa ideia usar uma chamada de função na expressão filter sempre que filter precisar fazer algo complexo. Avaliar a expressão causa a execução da função, nesse caso, Eval_Exception
.
Observe o uso de GetExceptionCode
para determinar a exceção. Essa função deve ser chamada dentro da expressão de filtro da instrução __except
. Eval_Exception
não pode chamar GetExceptionCode
, mas deve ter o código de exceção passado para ele.
Esse manipulador passa o controle para outro manipulador, a menos que a exceção seja um inteiro ou um estouro de ponto flutuante. Se for, o manipulador chama uma função (HandleOverflow
é apenas um exemplo, não uma função de API) para tentar se recuperar adequadamente da exceção. O bloco de instruções __except
, que neste exemplo está vazio, nunca pode ser executado porque Eval_Exception
nunca retorna EXCEPTION_EXECUTE_HANDLER
(1).
Usar uma chamada de função é uma boa técnica de uso geral para lidar com expressões de filtro complexas. Outros dois recursos da linguagem C úteis são:
O operador condicional
O operador vírgula
O operador condicional é frequentemente útil aqui. Ele pode ser usado para verificar se há um código de retorno específico e retornar um de dois valores diferentes. Por exemplo, o filtro no código a seguir confirma a exceção apenas se a exceção for STATUS_INTEGER_OVERFLOW
:
__except (GetExceptionCode() == STATUS_INTEGER_OVERFLOW ? 1 : 0)
O propósito do operador condicional nesse caso é basicamente fornecer clareza, pois o código a seguir gera os mesmos resultados:
__except (GetExceptionCode() == STATUS_INTEGER_OVERFLOW)
O operador condicional é mais útil em situações em que talvez você queira que o filtro seja avaliado em -1,EXCEPTION_CONTINUE_EXECUTION
.
O operador de vírgula permite executar várias expressões em sequência. Em seguida, retorna o valor da última expressão. Por exemplo, o código a seguir armazena o código de exceção em uma variável e o testa:
__except (nCode = GetExceptionCode(), nCode == STATUS_INTEGER_OVERFLOW)
Confira também
Escrevendo um manipulador de exceções
Tratamento de exceções estruturado (C/C++)