O que você parece ser pego é o inferno específico de alguém tentando comer seu bolo e também comê-lo.
RAII e exceções são projetadas para andar de mãos dadas. RAII é o meio pelo qual você não precisa escrever muitas catch(...)
instruções 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 catch
declaração pode fazer uma de duas coisas: lidar com um erro ou circunstância excepcional ou executar um trabalho de limpeza. Às vezes, ele faz as duas coisas, mas catch
existe toda declaração para fazer pelo menos uma delas.
catch(...)
é incapaz de executar um tratamento de exceção adequado. 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 uma exceção ter sido lançada por algo dentro de um determinado bloco de código. A única coisa legítima que você pode fazer nesse bloco é fazer a limpeza. E isso significa repetir a exceção no final da limpeza.
O que RAII oferece a você em relação ao tratamento de exceções é a limpeza gratuita. Se tudo estiver encapsulado corretamente em RAII, tudo será limpo corretamente. Você não precisa mais ter catch
instruções para limpar. Nesse caso, não há razão para escrever uma catch(...)
declaração.
Então, eu concordo que isso catch(...)
é principalmente mau ... provisoriamente .
Essa disposição é o uso adequado da RAII. Porque sem ele, você precisa ser capaz de fazer determinada limpeza. Não há como fugir disso; você precisa ser capaz de fazer o trabalho de limpeza. Você precisa garantir que a emissão de uma exceção deixe o código em um estado razoável. E catch(...)
é uma ferramenta vital para 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 deles; caso contrário, você não será seguro para exceções.
Claro, há um uso válido, embora raro, catch(...)
que nem a RAII pode banir: exception_ptr
encaminhar para outra pessoa. Normalmente através de uma promise/future
interface ou similar.
Meus colegas de trabalho dizem que você sempre deve saber quais exceções devem ser lançadas e que sempre pode usar construções como:
Seu colega de trabalho é um idiota (ou apenas terrivelmente ignorante). Isso deve ser imediatamente óbvio devido à quantidade de código de copiar e colar que ele sugere que você escreva. A limpeza para cada uma dessas instruções de captura será exatamente a mesma . Isso é um pesadelo de manutenção, sem 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 é o contrário de como a maioria das pessoas argumenta que a RAII é ruim. Geralmente, o argumento diz "RAII é ruim porque você precisa usar exceções para sinalizar falha no construtor. Mas você não pode lançar exceções, porque não é seguro e terá que ter muitas catch
instruções para limpar tudo". O que é um argumento quebrado, porque o RAII resolve o problema que a falta de RAII cria.
Provavelmente, ele é contra a RAII porque esconde detalhes. As chamadas de destruidor não são visíveis imediatamente nas variáveis automáticas. Então você obtém um código chamado implicitamente. Alguns programadores realmente odeiam isso. Aparentemente, até o ponto em que eles acham que ter três catch
instruções, todas as quais fazem o mesmo com o código de copiar e colar, é uma idéia melhor.
...
", enquanto meu foco pergunta sobre "Devo melhor captura...
ou<specific exception>
antes rethrowing"