Erros e manipulação de exceção (guia de programação C++ moderno)
No C++ moderno, na maioria das situações, a melhor maneira de relatar e tratar erros de tempo de execução e erros de lógica é usar exceções.Isso é especialmente verdadeiro quando a pilha pode conter várias chamadas de função entre a função de detecta o erro e a função que tem o contexto para saber como lidar com ele.Exceções fornecem uma maneira formal e bem definida para o código que detecta erros para passar as informações de pilha de chamadas.
Erros de programa geralmente são divididos em duas categorias: erros de lógica são causados por erros de programação por exemplo, um erro "Índice fora do intervalo" e erros de runtime que estão além do controle de programador, por exemplo, um erro de "rede de serviço não disponível".Relatório de erros é gerenciado em programação estilo c e COM, retornando um valor que representa um código de erro ou um código de status para uma função específica ou definindo uma variável global que o chamador pode, opcionalmente, recuperar após cada chamada de função para ver se os erros foram relatados.Por exemplo, programação COM usa o valor de retorno HRESULT para comunicar erros ao chamador e a API Win32 tem a função GetLastError para recuperar o último erro foi relatado pela pilha de chamadas.Em ambos os casos, cabe ao chamador para o código de reconhecer e responder apropriadamente.Se o chamador não tratar explicitamente o código de erro, o programa pode falhar sem aviso ou continuar a executar com dados incorretos e produzir resultados incorretos.
Exceções são preferenciais em C++ modernos pelos seguintes motivos:
Uma exceção força o código de chamada para reconhecer uma condição de erro e lidar com ele.Exceções sem tratamento parar a execução do programa.
Uma exceção vai para o ponto na pilha de chamadas pode manipular o erro.Funções intermediárias podem deixar que a exceção propagar.Não é necessário coordenar com outras camadas.
O mecanismo de desenrolamento de pilha de exceção destrói todos os objetos no escopo de acordo com regras bem definidas após uma exceção é lançada.
Uma exceção permite uma separação clara entre o código que detecta o erro e o código que manipula o erro.
Exemplo simplificado a seguir mostra a sintaxe necessária para lançar e capturar exceções em C++.
#include <stdexcept>
#include <limits>
#include <iostream>
using namespace std;
class MyClass
{
public:
void MyFunc(char c)
{
if(c < numeric_limits<char>::max())
throw invalid_argument("MyFunc argument too large.");
//...
}
};
int main()
{
try
{
MyFunc(256); //oops!
}
catch(invalid_argument& e)
{
cerr << e.what() << endl;
return -1;
}
//...
return 0;
}
Exceções em C++ são semelhantes àquelas em linguagens como C# e Java.No try bloquear, se uma exceção é lançada será pego pelos primeiros associados catch bloco cujo tipo corresponde ao que a exceção.Em outras palavras, a execução saltará do throw instrução para o catch instrução.Não se for encontrado nenhum bloco catch utilizável, std::terminate é invocado e sai do programa.No C++, qualquer tipo pode ser lançado; No entanto, recomendamos que você lançar um tipo que deriva direta ou indiretamente de std::exception.No exemplo anterior, o tipo de exceção, invalid_argument, definidas na biblioteca padrão na <stdexcept> arquivo de cabeçalho.C++ não fornece e não exige uma finally bloco para certificar-se de que todos os recursos serão liberados se uma exceção é lançada.A aquisição de recurso é o idioma de inicialização (RAII), que usa ponteiros inteligentes, fornece a funcionalidade necessária para limpeza de recursos.Para mais informações, consulte Como: Design para segurança de exceção (C++).Para obter informações sobre o mecanismo de desenrolamento de pilha do C++, consulte Exceções e pilha desenrolar em C++.
Diretrizes básicas
Tratamento de erro robustos é desafiador em qualquer linguagem de programação.Embora exceções fornecem vários recursos que oferecem suporte a tratamento de erro bom, eles não podem fazer todo o trabalho para você.Para obter os benefícios do mecanismo de exceção, ter exceções em mente ao projetar seu código.
Usar declarações para verificar erros que nunca devem ocorrer.Use exceções para verificar erros que possam ocorrer, por exemplo, erros de validação de entrada nos parâmetros de funções públicas.Para mais informações, consulte Exceptions VS. Assertions.
Use exceções quando o código que manipula o erro pode ser separado do código que detecta o erro por um ou mais chamadas de função intervenientes.Considere se deseja usar códigos de erro em vez em loops de desempenho essenciais ao código que manipula o erro está intimamente ligado ao código que detecta.Para obter mais informações sobre quando não usar exceções, consulte When Not to Use Exceptions.
Para cada função que pode lançar ou propagar uma exceção, fornecer garantias de três exceções: forte garantia, garantia básica ou garantia nothrow (noexcept).Para mais informações, consulte Como: Design para segurança de exceção (C++).
Lançar exceções por valor, capturá-las por referência.Não catch não pode manipular.Para mais informações, consulte Diretrizes para lançar e capturar exceções (C++).
Não use as especificações de exceção, preteridas no C + + 11.Para mais informações, consulte Exception specifications and noexcept.
Use tipos de exceções da biblioteca padrão quando eles se aplicam.Derivar tipos de exceção personalizada do classe de exceção hierarquia.Para mais informações, consulte Como: usar os objetos de exceção de biblioteca padrão.
Não permitir exceções para escape de destruidores ou funções de desalocação de memória.
Exceções e desempenho
O mecanismo de exceção tem um desempenho mínimo custo se nenhuma exceção é lançada.Se uma exceção é lançada, o custo de passagem de pilha e desenrolamento são aproximadamente comparável ao custo de uma chamada de função.Estruturas de dados adicionais são necessárias para controlar a pilha de chamada após um try bloco é inserido e instruções adicionais são necessárias para desenrolar a pilha se uma exceção é lançada.No entanto, na maioria dos cenários, o custo de espaço de memória e desempenho não é significativo.O efeito adverso de exceções no desempenho provavelmente ser significativas somente em sistemas de memória muito restrita ou no desempenho crítico loops onde um erro é provável que ocorra regularmente e o código para manipulá-lo está intimamente ligado ao código que informa.Em qualquer caso, é impossível saber o custo real de exceções sem criação de perfil e medição.Mesmo em casos raros quando o custo é significativo, você pode avaliá-lo contra a maior correção, manutenção mais fácil e outras vantagens oferecidas por uma diretiva de exceção bem projetada.
Exceções VS. asserções
Exceções e declarações são dois mecanismos distintos para detectar erros de tempo de execução em um programa.Usar declarações para testar condições durante o desenvolvimento nunca deve ser true se todo o código está correto.Não há nenhum ponto no tratamento de erro usando uma exceção porque o erro indica que algo no código foi corrigido e não representam uma condição que tem o programa para a recuperação de tempo de execução.Um assert interrompe a execução na instrução para que você pode inspecionar o estado do programa no depurador; uma exceção continua a execução do manipulador catch apropriada de primeira.Use exceções para verificar as condições de erro podem ocorrer em tempo de execução, mesmo se o código está correto, por exemplo, "arquivo não encontrado" ou "sem"memória. Convém recuperar essas condições, mesmo que a recuperação apenas gera uma mensagem para um log e termina o programa.Sempre verifique os argumentos para funções públicas usando exceções.Mesmo se sua função é livre de erros, você não pode ter controle completo sobre os argumentos que um usuário pode passar para ele.
Exceções do C++ versus Exceções SEH do Windows
Programas c e C++ podem usar a mecanismo de (SEH) no sistema operacional Windows de manipulação de exceção estruturada.Os conceitos de SEH são semelhantes àquelas de exceções do C++, exceto que usa o SEH o __try, __except, e __finally construções em vez de try e catch.No Visual C++, exceções do C++ são implementadas para SEH.No entanto, quando você escrever código C++, use a sintaxe de exceção do C++.
Para obter mais informações sobre o SEH, consulte (C++) de manipulação de exceção estruturada.
Noexcept e especificações de exceção
Especificações de exceção foram introduzidas em C++ como uma maneira de especificar que uma função pode lançar exceções.No entanto, especificações de exceção provou problemáticas na prática e preteridas no C + + padrão rascunho 11.Recomendamos que você não usar as especificações de exceção, exceto throw(), que indica que a exceção permite sem exceções de escape.Se você deve usar as especificações de exceção do tipo throw(tipo), esteja ciente de que Visual C++ entregas do padrão de determinadas maneiras.Para mais informações, consulte Especificações de exceção.O noexcept especificador é introduzido no C + + 11 como a alternativa preferida para throw().
Consulte também
Conceitos
Como: Interface entre o código-excepcional e excepcional