Como posso capturar todos os tipos de exceções em um bloco catch?
-
09-06-2019 - |
Pergunta
Em C++, estou tentando capturar todos os tipos de exceções em uma única captura (como catch(Exception)
em C#).Como isso é feito?E mais, como capturar exceções de divisão por zero?
Solução
catch (...)
{
// Handle exceptions not covered.
}
Considerações importantes:
- Uma abordagem melhor é capturar tipos específicos de exceções das quais você pode realmente se recuperar, em oposição a todas as exceções possíveis.
- catch(...) também capturará certas exceções sérias no nível do sistema (varia dependendo do compilador) das quais você não será capaz de recuperar de forma confiável.Capturá-los dessa maneira e depois engoli-los e continuar pode causar mais problemas sérios em seu programa.
- Dependendo do seu contexto, pode ser aceitável usar catch(...), desde que a exceção seja lançada novamente.Nesse caso, você registra todas as informações úteis do estado local e, em seguida, lança novamente a exceção para permitir que ela se propague.No entanto, você deve ler sobre o Padrão RAII se você escolher esta rota.
Outras dicas
Você não quero usar catch (...) (ou seja,pegue com as reticências), a menos que você realmente, definitivamente, provavelmente tenha necessidade disso.
A razão para isso é que alguns compiladores (Visual C++ 6, para citar os mais comuns) também transformam erros como falhas de segmentação e outras condições realmente ruins em exceções que você pode manipular com prazer usando catch (...).Isso é muito ruim, porque você não vê mais os travamentos.
E tecnicamente, sim, você também pode capturar a divisão por zero (você terá que usar o "StackOverflow" para isso), mas você realmente deveria evitar fazer tais divisões em primeiro lugar.
Em vez disso, faça o seguinte:
- Se você realmente sabe que tipo de exceção esperar, capture esses tipos e nada mais, e
- Se você mesmo precisar lançar exceções e capturar todas as exceções que lançará, faça com que essas exceções derivem de std::exception (como sugeriu Adam Pierce) e capture-as.
Se você estiver no Windows e precisar lidar com erros como divisão por zero e violação de acesso, poderá usar um tradutor de exceção estruturado.E então dentro do seu tradutor você pode lançar uma exceção c++:
void myTranslator(unsigned code, EXCEPTION_POINTERS*)
{
throw std::exception(<appropriate string here>);
}
_set_se_translator(myTranslator);
Observe que o código informará qual foi o erro.Além disso, você precisa compilar com a opção /EHa (C/C++ -> Code Generatrion -> Enable C/C++ Exceptions = Yes with SEH Exceptions).
Se isso não fizer sentido, verifique a documentação de [_set_se_translator](http://msdn.microsoft.com/en-us/library/5z4bw5h5(VS.80).aspx)
Se capturar todas as exceções - incluindo as do sistema operacional - é realmente o que você precisa, dê uma olhada no seu compilador e no sistema operacional.Por exemplo, no Windows você provavelmente tem a palavra-chave "__try" ou a opção do compilador para fazer "try/catch" capturar exceções SEH, ou ambos.
Faça com que todas as suas classes de exceção personalizadas herdem de std::exception, então você pode simplesmente capturar std::exception.Aqui está um exemplo de código:
class WidgetError
: public std::exception
{
public:
WidgetError()
{ }
virtual ~WidgetError() throw()
{ }
virtual const char *what() const throw()
{
return "You got you a widget error!";
}
};
Em C++, o padrão não define uma exceção de divisão por zero e as implementações tendem a não lançá-las.
Você pode, é claro, usar catch (...) { /* code here */ }
, mas realmente depende do que você deseja fazer.Em C++ você tem destruidores determinísticos (nenhuma dessas besteiras de finalização), então se você quiser limpar, o correto a fazer é usar RAII.
Por exemplo.em vez de:
void myfunc()
{
void* h = get_handle_that_must_be_released();
try { random_func(h); }
catch (...) { release_object(h); throw; }
release_object(h);
}
Faça algo como:
#include<boost/shared_ptr.hpp>
void my_func()
{
boost::shared_ptr<void> h(get_handle_that_must_be_released(), release_object);
random_func(h.get());
}
Crie sua própria classe com um destruidor se você não usar o boost.
Se bem me lembro (já faz um tempo que não vejo C++), acho que o seguinte deve resolver
try
{
// some code
}
catch(...)
{
// catch anything
}
e um rápido google (http://www.oreillynet.com/pub/a/network/2003/05/05/cpluspocketref.html) parece provar que estou correto.