Diferença: std :: runtime_error vs std :: exception ()

128

Qual é a diferença entre std::runtime_errore std::exception? Qual é o uso apropriado para cada um? Por que eles são diferentes em primeiro lugar?

sivabudh
fonte

Respostas:

153

std::exceptioné a classe cujo único objetivo é servir como classe base na hierarquia de exceções. Não tem outros usos. Em outras palavras, conceitualmente é um classe abstrata (mesmo que não seja definida como classe abstrata no significado C ++ do termo).

std::runtime_erroré uma classe mais especializada, descendente de std::exception, destinada a ser lançada em caso de vários erros de tempo de execução . Tem um duplo objetivo. Ele pode ser lançado sozinho ou pode servir como uma classe base para vários tipos ainda mais especializados de exceções de erro de tempo de execução, como std::range_error, std::overflow_erroretc. Você pode definir suas próprias classes de exceção descendentes destd::runtime_error e também sua própria exceção classes descendentes de std::exception.

Assim como std::runtime_error, a biblioteca padrão contém std::logic_error, também descendentes std::exception.

O objetivo de ter essa hierarquia é dar ao usuário a oportunidade de usar todo o poder do mecanismo de manipulação de exceção do C ++. Como a cláusula 'catch' pode capturar exceções polimórficas, o usuário pode escrever cláusulas 'catch' que podem capturar tipos de exceção de uma subárvore específica da hierarquia de exceções. Por exemplo, catch (std::runtime_error& e)captará todas as exceções da std::runtime_errorsubárvore, permitindo que todas as outras passem (e voem ainda mais na pilha de chamadas).

PS Projetar uma hierarquia útil de classes de exceção (que permitiria capturar apenas os tipos de exceção nos quais você está interessado em cada ponto do seu código) é uma tarefa não trivial. O que você vê na biblioteca C ++ padrão é uma abordagem possível, oferecida a você pelos autores da linguagem. Como você vê, eles decidiram dividir todos os tipos de exceção em "erros de tempo de execução" e "erros lógicos" e permitem prosseguir a partir daí com seus próprios tipos de exceção. É claro que existem maneiras alternativas de estruturar essa hierarquia, que podem ser mais apropriadas em seu design.

Atualização: Portabilidade Linux vs Windows

Como Loki Astari e unixman83 observaram em suas respostas e comentários abaixo, o construtor da exceptionclasse não aceita argumentos de acordo com o padrão C ++. O Microsoft C ++ possui um construtor que aceita argumentos na exceptionclasse, mas isso não é padrão. A runtime_errorclasse tem um construtor recebendo argumentos (char* ) nas duas plataformas, Windows e Linux. Para ser portátil, use melhor runtime_error.

(E lembre-se, apenas porque uma especificação do seu projeto diz que seu código não precisa ser executado no Linux, isso não significa que ele nunca precisa ser executado no Linux.)

Formiga
fonte
1
obrigado. Ótima resposta. embora eu me pergunte se há alguma necessidade de ter um tipo diferente de exceção ... apenas um pensamento.
Sivabudh 15/10/09
1
Se houver uma possibilidade de cobertura da exceção, um tipo diferente de exceção poderá ser útil, pois podemos usar o mecanismo de tratamento de exceções para direcionar a exceção ao manipulador que tentará corrigir o problema. Se não houver chance de recuperação, uma das exceções padrão está correta.
Martin Iorque
1
Apenas como um aparte: não existe regra, em lugar algum, que o force a derivar std::exception. Claro, todas as stdcoisas lançam classes derivadas disso, mas não há absolutamente nenhuma razão para lançar apenas std::exceptionobjetos derivados.
rubenvb
1
@ Rubenvb Eu não sabia disso, mas acho que vai esclarecer o código para manutenção futura se apenas objetos de classes derivadas de exceção forem lançados. Exemplo: gosto de descobrir quais exceções personalizadas são implementadas na minha base de código e procurar classes derivadas da exceção.
precisa saber é o seguinte
21

std::exceptiondeve ser considerada (observe o considerado) a base abstrata da hierarquia de exceções padrão. Isso ocorre porque não há mecanismo para transmitir uma mensagem específica (para fazer isso, você deve derivar e se especializar what()). Não há nada que o impeça de usar std :: exception e, para aplicativos simples, pode ser tudo o que você precisa.

std::runtime_errorpor outro lado, possui construtores válidos que aceitam uma string como uma mensagem. Quando what()é chamado um ponteiro const char, é retornado que aponta para uma string C que possui a mesma string que foi passada para o construtor.

try
{
    if (badThingHappened)
    {
         throw std::runtime_error("Something Bad happened here");
    }
}
catch(std::exception const& e)
{
    std::cout << "Exception: " << e.what() << "\n";
} 
Martin York
fonte
1
Obrigado pela resposta Martin. No entanto, eu uso std :: exception () da mesma maneira que você descreveu acima. ou seja, o construtor std :: exception () também pode usar std :: string () ou const char *.
Sivabudh 16/10/09
14
Não de acordo com o padrão. std :: exception possui um construtor que não aceita argumentos. O uso de uma versão que aceita uma std :: string ou uma C-String não é portátil.
Martin York
10
Por causa da Microsoft, eu me acostumei a jogar std::exception(std::string). Agora percebo que devo jogar std::runtime_errorse quiser que meu código funcione no Linux (GCC).
unixman83