De volta à escola, há mais de 10 anos, eles estavam ensinando você a usar especificadores de exceção. Como meu histórico é como um dos programadores Torvaldish C que evita teimosamente o C ++, a menos que seja forçado, eu só acabo no C ++ esporadicamente, e quando uso ainda uso especificadores de exceção, pois foi o que me ensinaram.
No entanto, a maioria dos programadores de C ++ parece desaprovar os especificadores de exceção. Eu li o debate e os argumentos de vários gurus de C ++, como estes . Tanto quanto eu entendo, tudo se resume a três coisas:
- Os especificadores de exceção usam um sistema de tipos que é inconsistente com o restante do idioma ("sistema de tipos de sombra").
- Se sua função com um especificador de exceção lançar outra coisa, exceto o que você especificou, o programa será encerrado de maneiras ruins e inesperadas.
- Os especificadores de exceção serão removidos no próximo padrão C ++.
Estou faltando alguma coisa aqui ou essas são todas as razões?
Minhas próprias opiniões:
Em relação a 1): E daí? C ++ é provavelmente a linguagem de programação mais inconsistente já criada, em termos de sintaxe. Temos as macros, os goto / labels, a horda (horda?) De comportamento indefinido / não especificado / definido pela implementação, os tipos inteiros mal definidos, todas as regras implícitas de promoção de tipos, palavras-chave implícitas de promoção, palavras-chave de caso especial como friend, auto , registrar, explícito ... E assim por diante. Alguém provavelmente poderia escrever vários livros grossos de toda a estranheza em C / C ++. Então, por que as pessoas estão reagindo contra essa inconsistência específica, que é uma falha menor em comparação com muitas outras características muito mais perigosas da linguagem?
Em relação a 2): Essa não é minha responsabilidade? Existem muitas outras maneiras de escrever um bug fatal em C ++. Por que esse caso em particular é pior? Em vez de escrever throw(int)
e depois lançar Crash_t, posso também afirmar que minha função retorna um ponteiro para int, depois cria um tipo de letra explícito e selvagem e retorna um ponteiro para um Crash_t. O espírito do C / C ++ sempre foi deixar a maior parte da responsabilidade para o programador.
E as vantagens, então? O mais óbvio é que, se sua função tentar lançar explicitamente qualquer tipo diferente do que você especificou, o compilador apresentará um erro. Eu acredito que o padrão é claro em relação a isso (?). Os erros só acontecem quando sua função chama outras funções que, por sua vez, lançam o tipo errado.
Vindo de um mundo de programas C determinísticos e incorporados, eu certamente preferiria saber exatamente o que uma função jogará para mim. Se houver algo no idioma que suporte isso, por que não usá-lo? As alternativas parecem ser:
void func() throw(Egg_t);
e
void func(); // This function throws an Egg_t
Acho que há uma grande chance de o chamador ignorar / esquecer de implementar o try-catch no segundo caso, menos no primeiro caso.
Pelo que entendi, se uma dessas duas formas decidir lançar repentinamente outro tipo de exceção, o programa falhará. No primeiro caso, porque não é permitido lançar outra exceção, no segundo caso, porque ninguém esperava lançar um SpanishInquisition_t e, portanto, essa expressão não é capturada onde deveria estar.
No caso deste último, ter algumas capturas de último recurso (...) no nível mais alto do programa não parece realmente melhor do que uma falha no programa: "Ei, em algum lugar do seu programa, algo lançou uma exceção estranha e sem tratamento . " Você não pode recuperar o programa quando estiver longe de onde a exceção foi lançada, a única coisa que você pode fazer é sair do programa.
E, do ponto de vista do usuário, eles não se importariam se recebessem uma caixa de mensagens maliciosas do sistema operacional dizendo "Programa encerrado. Blablabla no endereço 0x12345" ou uma caixa de mensagens maliciosas do seu programa dizendo "Exceção não tratada: minha classe. func.something ". O bug ainda está lá.
Com o próximo padrão C ++, não terei outra opção senão abandonar os especificadores de exceção. Mas eu preferiria ouvir algum argumento sólido sobre por que eles são ruins, em vez de "Sua Santidade declarou isso e é assim". Talvez haja mais argumentos contra eles do que os que listei, ou talvez haja mais deles do que imagino?
Respostas:
As especificações de exceção são ruins porque são pouco aplicadas e, portanto, não realizam muito, e também são ruins porque forçam o tempo de execução a procurar exceções inesperadas para que possam terminar (), em vez de invocar o UB , isso pode desperdiçar uma quantidade significativa de desempenho.
Portanto, em resumo, as especificações de exceção não são aplicadas com força suficiente no idioma para tornar o código mais seguro, e implementá-las conforme especificado foi uma grande perda de desempenho.
fonte
Uma razão pela qual ninguém as usa é porque sua suposição primária está errada:
Este programa é compilado sem erros ou avisos .
Além disso, mesmo que a exceção tivesse sido detectada , o programa ainda é encerrado.
Editar: para responder a um ponto da sua pergunta, pegar (...) (ou melhor, pegar (std :: exeption &) ou outra classe base e depois pegar (...)) ainda é útil, mesmo que você não o faça. saber exatamente o que deu errado.
Considere que seu usuário apertou um botão de menu para "salvar". O manipulador do botão de menu convida o aplicativo a salvar. Isso pode falhar por inúmeras razões: o arquivo estava em um recurso de rede que desapareceu, havia um arquivo somente leitura e não pôde ser salvo, etc. Mas o manipulador realmente não se importa por que algo falhou; só se preocupa se conseguiu ou falhou. Se conseguiu, tudo está bem. Se falhar, pode informar ao usuário. A natureza exata da exceção é irrelevante. Além disso, se você escrever um código adequado e seguro para exceções, isso significa que qualquer erro desse tipo pode se propagar pelo sistema sem derrubá-lo - mesmo para códigos que não se importam com o erro. Isso facilita a extensão do sistema. Por exemplo, agora você salva por meio de uma conexão com o banco de dados.
fonte
Esta entrevista com Anders Hejlsberg é bastante famosa. Nele, ele explica por que a equipe de design do C # descartou exceções verificadas em primeiro lugar. Em poucas palavras, existem dois motivos principais: capacidade de versão e escalabilidade.
Eu sei que o OP está focado em C ++, enquanto Hejlsberg está discutindo C #, mas os pontos que Hejlsberg destaca também são perfeitamente aplicáveis a C ++.
fonte