Compartilhar via


Como: Design para segurança de exceção (C++)

Uma das vantagens do mecanismo de exceção é que a execução, juntamente com dados sobre a exceção, vai diretamente da instrução que gera a exceção para a primeira instrução catch que manipula ele.O manipulador pode ser qualquer número de níveis acima na pilha de chamadas.As funções que são chamadas entre a instrução try e a instrução throw não precisam saber nada sobre a exceção que é lançada.No entanto, eles precisam ser criados para que eles sair do escopo “inesperada” em qualquer ponto de onde uma exceção pode se propagar para cima e baixo, para fazer isso sem sair code-behind objetos criados, parcialmente de memória vazada, ou estruturas de dados que estão em estados inutilizáveis.

Técnicas básicas

Uma diretiva robusta de manipulação de exceção requer o pensamento cuidadoso e deve ser parte do processo de design.Em geral, a maioria das exceções detectadas e são geradas em camadas inferiores de um módulo de software, mas essas camadas normalmente não têm suficientes contexto para manipular o erro ou para exibir uma mensagem aos usuários finais.Em camadas médios, as funções podem capturar e relançar uma exceção quando inspecionar têm que o objeto de exceção, ou têm informações úteis adicional para prever a camada superior que captura finalmente a exceção.Uma função deve engulir” e “capturar uma exceção somente se pode recuperar completamente de ela.Em muitos casos, o comportamento correto em camadas médias é permitir que uma bolha exceção da a pilha de chamadas.Mesmo na camada mais alta, pode ser apropriada permitir que uma exceção não tratada finalizar um programa se a exceção permite que o programa em um estado em que sua exatidão não pode ser garantida.

Não importa como uma função lida com uma exceção, para ajudar a garantir que é seguro “inserção,” deve ser criada de acordo com as seguintes regras básicas.

Hh279653.collapse_all(pt-br,VS.110).gifManter classes de recursos simples

Quando você encapsula o gerenciamento de recursos manual classes, use uma classe que não faz nada mais gerenciar cada recurso; caso contrário, você pode introduzir vazamentos.

Hh279653.collapse_all(pt-br,VS.110).gifUse o idioma de RAII para gerenciar recursos

Para ser inserção, segura uma função deve garantir que os objetos que tiver atribuído usando malloc ou new serão destruídos, e todos os recursos como os identificadores de arquivo são fechadas ou liberados se uma exceção é lançada.O idioma Aquisição de recursos é Inicialização (RAII) amarra o gerenciamento de tais recursos ao tempo de variáveis automáticas.Quando uma função sai do escopo, retornando normalmente ou por causa de uma exceção, os destruidores para todas as variáveis automático completos construídos são chamados.Um objeto invólucro de RAII como um ponteiro inteligente chama a função apropriada de excluir ou final no destrutor.No código de manipulação criticamente seguro, é importante passar imediatamente a propriedade de cada recurso para qualquer tipo de objeto de RAII.Observe que vector, string, make_shared, fstream, e classes tratam semelhantes a aquisição de recurso para você. No entanto, unique_ptr e as compilações tradicionais de shared_ptr são especiais porque a aquisição de recursos é executada pelo usuário em vez do objeto; como consequência, contam como a versão do recurso é destruição mas são duvidosos como RAII.

As três garantias de exceção

Normalmente, a segurança de exceção é discutida em termos de três garantias de exceção que pode fornecer uma função: a garantia da não falhar, a garantiade alta segurança, e a garantia básica.

Hh279653.collapse_all(pt-br,VS.110).gifSem garantia de falha

A garantia da falha (sem ou, “sem throw”) é a garantia para mais segura que uma função pode fornecer.Indica que a função não lança uma exceção ou não permitirá que se propague.No entanto, você não pode fornecer tal confiavelmente garantia a menos que a você () souberem que todas as funções que este as chamadas de função são também não falhar, ou (b) você aprender a qual todas as exceções que são geradas são capturadas antes que elas atinjam essa função ctype (), ou você aprender capturar e manipular corretamente todas as exceções que podem acessar essa função.

A garantia forte e a garantia básica contam com a suposição que os destruidores são sem falhar.Todos os recipientes e tipos na garantia padrão da biblioteca que os destruidores não lançam.Há também um requisito para trás: A biblioteca padrão requer que os tipos definidos pelo usuário que são dados - para o exemplo, porque o modelo argumento- deve ter destruidores de jogos.

Hh279653.collapse_all(pt-br,VS.110).gifGarantia forte

A garantia de que indica se uma função sai do escopo por causa de uma exceção, não escapará a memória e estado de programa não será alterado.Uma função que fornece uma garantia forte é essencialmente uma transação que possui a semântica de confirmação ou reversão: êxito ou completamente ou não tem efeito.

Hh279653.collapse_all(pt-br,VS.110).gifGarantia básica

A garantia básica é a mais de três fraca.No entanto, talvez seja a melhor opção quando uma garantia forte é muito cara consumo de memória ou desempenho.A garantia básica que indica se uma exceção ocorrer, nenhuma memória é vazada e o objeto ainda está em um estado útil mesmo que os dados podem ter sido alterados.

Segurança de classes de exceção

Uma classe pode ajudar a assegurar sua própria segurança de exceção, mesmo quando é consumida por funções não seguro, impedindo que se é construída ou parcialmente parcialmente destrui-lo.Se um construtor de classe termina antes de conclusão, o objeto é criado e o destrutor nunca será chamado nunca.Embora as variáveis automática que são inicializados antes de exceção tenham os destruidores a memória ou recursos chamados, dinamicamente atribuídos que não são gerenciados por um ponteiro inteligente ou por uma variável automática será semelhante de escape.

Os tipos internos são qualquer sem falhar, e os tipos padrão da biblioteca oferece suporte a garantia básica no mínimo.Siga estas diretrizes para qualquer tipo definido pelo usuário segura que devem ser exceção:

  • Use ponteiros inteligentes ou outros conteúdos de RAII- tipo para gerenciar todos os recursos.Evite a funcionalidade de gerenciamento de recursos no destrutor da classe, porque o destrutor não será chamado se o construtor gera uma exceção.No entanto, se a classe é um recurso dedicado controle que apenas um recurso, então é aceitável usar o destrutor para gerenciar recursos.

  • Entender que uma exceção lançada em um construtor de classe base não pode ser engulida em um construtor de classe derivada.Se você deseja converter e relançar a exceção da classe base de um construtor derivada, use um bloco try de função.Para obter mais informações, consulte Como: tratar exceções em construtores de classe Base (C++).

  • Considere armazenar especialmente se qualquer estado de um membro de dados que é empacotado em um ponteiro inteligente, se uma classe tem um conceito de “inicialização que é permitida falhar.” Embora C++ permite membros não inicializado de dados, não suporta instâncias de classe não inicializado ou parcialmente inicializadas.Um construtor deve obterá êxito ou falhar; nenhum objeto é criado se o construtor não executa a conclusão.

  • Não permita que nenhuma exceções escapem de um destrutor.Um axioma básico C++ é que os destruidores nunca deve permitir que uma exceção propague à pilha de chamadas.Se um destrutor deve executar uma operação potencial de jogo, deve fazer isso em um bloco catch try e engulir a exceção.A biblioteca padrão fornece essa garantia em todos os destruidores que define.

Consulte também

Conceitos

Erros e manipulação de exceção (guia de programação C++ moderno)

Como: Interface entre o código-excepcional e excepcional