Ao projetar minha primeira biblioteca C ++ 'séria', estou me perguntando:
É bom estilo derivar exceções std::exception
e seus descendentes ?!
Mesmo depois de ler
- Projetando classes de exceção
- O que é um 'bom número' de exceções a serem implementadas na minha biblioteca?
Ainda não tenho certeza. Porque, além da prática comum (mas talvez não seja boa), eu assumiria, como usuário da biblioteca, que uma função da biblioteca lançaria std::exception
s somente quando as funções da biblioteca padrão falharem na implementação da biblioteca, e não poderá fazer nada a respeito. Mas ainda assim, ao escrever o código do aplicativo, para mim é muito conveniente, e também IMHO de boa aparência apenas para lançar um std::runtime_error
. Além disso, meus usuários também podem confiar na interface mínima definida, como what()
códigos ou.
E, por exemplo, meu usuário fornece argumentos defeituosos, o que seria mais conveniente do que lançar um std::invalid_argument
, não? Então, combinado com o uso ainda comum de std :: exception que vejo nos outros códigos: Por que não ir ainda mais longe e derivar de sua classe de exceção personalizada (por exemplo, lib_foo_exception) e também de std::exception
.
Pensamentos?
fonte
std::exception
não significa que você jogou astd::exception
. Além disso,std::runtime_error
herda destd::exception
em primeiro lugar, e owhat()
método vem destd::exception
, nãostd::runtime_error
. E você definitivamente deve criar suas próprias classes de exceção em vez de lançar exceções genéricas comostd::runtime_error
.lib_foo_exception
classe derivastd::exception
, o usuário da biblioteca capturarialib_foo_exception
apenas capturandostd::exception
, além de quando capturas apenas a biblioteca. Então, eu também poderia perguntar se minha classe raiz de exceção da biblioteca deve herdar de std :: exception .lib_foo_exception
?" Com a herança destd::exception
você pode fazê-lo porcatch(std::exception)
OU porcatch(lib_foo_exception)
. Sem derivarstd::exception
, você o capturaria se e somente se , porcatch(lib_foo_exception)
.catch(...)
. Está lá porque a linguagem permite o caso que você está considerando (e para "comportar-se mal" nas bibliotecas), mas isso não é uma prática recomendada moderna.catch
sites mais gerais e mais grossos, além de transações mais grossas que modelam uma operação final do usuário. Se você compará-lo a idiomas que não promovem a idéia de captura generalizadastd::exception&
, por exemplo, eles geralmente têm muito mais código comtry/catch
blocos intermediários preocupados com erros muito específicos, o que diminui um pouco a generalidade do tratamento de exceções quando ele começa a aparecer. uma ênfase muito mais forte no tratamento manual de erros e também em todos os erros díspares que poderiam ocorrer.Respostas:
Todas as exceções devem herdar de
std::exception
.Suponha, por exemplo, que eu precise ligar
ComplexOperationThatCouldFailABunchOfWays()
e que eu queira lidar com qualquer exceção que possa gerar. Se tudo é herdadostd::exception
, isso é fácil. Eu só preciso de um únicocatch
bloco e tenho uma interface padrão (what()
) para obter detalhes.Se as exceções NÃO herdam
std::exception
, isso fica muito mais feio:Sobre jogar
runtime_error
ou nãoinvalid_argument
criar suas própriasstd::exception
subclasses para jogar: Minha regra geral é introduzir uma nova subclasse sempre que eu precisar lidar com um tipo específico de erro de maneira diferente de outros erros (ou seja, sempre que eu precisar de umcatch
bloco separado ).runtime_error
jogado aqui significa diferente algo que um erro de execução genérico), então eu corro o risco de entrar em conflito com outros usos da subclasse existente.invalid_argument
), reutilizarei a classe existente. Só não vejo muitos benefícios em adicionar uma nova classe neste caso. (As Diretrizes Principais do C ++ discordam de mim aqui - elas recomendam sempre o uso de suas próprias classes.)As diretrizes principais do C ++ têm mais discussões e exemplos.
fonte
catch (...)
(com as reticências literais)?catch (...)
só é útil se você não precisar fazer nada com o que é lançado. Se você quiser fazer algo - por exemplo, mostrar ou registrar a mensagem de erro específica, como no meu exemplo -, precisará saber o que é.Essa é uma suposição incorreta.
Os tipos de exceção padrão são fornecidos para uso "mais comum". Eles não foram projetados apenas para serem usados pela biblioteca padrão.
Sim, faça com que tudo acabe herdado
std::exception
. Muitas vezes, isso envolve a herança destd::runtime_error
oustd::logic_error
. O que for apropriado para a classe de exceção que você está implementando.É claro que isso é subjetivo - várias bibliotecas populares ignoram completamente os tipos de exceção padrão, presumivelmente para separar as bibliotecas da biblioteca padrão. Pessoalmente, acho isso extremamente egoísta! Torna a captura de exceções muito mais difícil de acertar.
Falando pessoalmente, muitas vezes eu jogo
std::runtime_error
e acabo com isso. Mas isso está entrando em uma discussão sobre quão granular é fazer suas classes de exceção, e não é isso que você está perguntando.fonte