O que você parece estar preso é o inferno específico de alguém tentando ter seu bolo e comê-lo também.
RAII e exceções são projetadas para andar de mãos dadas. RAII é o meio pelo qual você não tem para gravar muitas instruções catch(...)
para fazer a limpeza. Isso acontecerá automaticamente, como é óbvio. E as exceções são a única maneira de trabalhar com objetos RAII, porque os construtores só podem ter sucesso ou lançar (ou colocar o objeto em um estado de erro, mas quem quer isso?).
Uma instrução catch
pode fazer uma das duas coisas: manipular um erro ou uma circunstância excepcional ou fazer um trabalho de limpeza. Às vezes, ele faz as duas coisas, mas todas as instruções catch
existem para fazer pelo menos uma delas.
catch(...)
é incapaz de fazer o tratamento adequado de exceções. Você não sabe qual é a exceção; você não pode obter informações sobre a exceção. Você não tem absolutamente nenhuma informação além do fato de que uma exceção foi lançada por algo dentro de um determinado bloco de código. A única coisa legítima que você pode fazer nesse tipo de bloqueio é fazer a limpeza. E isso significa re-lançar a exceção no final da limpeza.
O que o RAII lhe dá em relação ao tratamento de exceções é a limpeza gratuita. Se tudo estiver encapsulado em RAII corretamente, tudo será devidamente limpo. Você não precisa mais ter instruções catch
limpando. Nesse caso, não há motivo para escrever uma declaração catch(...)
.
Então, eu concordo que catch(...)
é principalmente mal ... provisoriamente .
Essa disposição é o uso adequado do RAII. Porque sem ele, você precisa para poder fazer certas limpezas. Não há como fugir disso; você tem que ser capaz de fazer o trabalho de limpeza. Você precisa ser capaz de garantir que lançar uma exceção deixará o código em um estado razoável. E catch(...)
é uma ferramenta vital ao fazer isso.
Você não pode ter um sem o outro. Você não pode dizer que ambos RAII e catch(...)
são ruins. Você precisa de pelo menos um desses; caso contrário, você não é uma exceção segura.
Claro, há um uso válido, embora raro, de catch(...)
que nem mesmo o RAII pode banir: recebendo um exception_ptr
para encaminhar para outra pessoa. Normalmente, através de uma interface promise/future
ou similar.
My coworkers says that you should always know what exceptions are to be thrown and that you can always use constructs like:
Seu colega de trabalho é um idiota (ou simplesmente ignorante). Isso deve ser imediatamente óbvio devido à quantidade de código para copiar e colar que ele sugere que você escreva. A limpeza de cada uma dessas declarações catch será exatamente a mesma . Isso é um pesadelo de manutenção, para não mencionar a legibilidade.
Resumindo: esse é o problema que o RAII foi criado para resolver (não que ele não resolva outros problemas).
O que me confunde sobre essa noção é que geralmente é de trás para a forma como a maioria das pessoas argumenta que RAII é ruim. Geralmente, o argumento é "RAII é ruim porque você tem que usar exceções para sinalizar falha de construtor. Mas você não pode lançar exceções, porque não é seguro e você terá que ter muitas instruções catch
para limpar tudo. " Qual é um argumento quebrado porque o RAII resolve o problema que a falta de RAII cria.
Mais do que provável, ele é contra RAII porque esconde detalhes. Chamadas de destruidor não são imediatamente visíveis em variáveis automáticas. Então você pega o código que é chamado implicitamente. Alguns programadores realmente odeiam isso. Aparentemente, ao ponto em que eles acham que ter 3% de declaraçõescatch
, todas fazem a mesma coisa com o código copiar e colar, é uma idéia melhor.