Sobes.tech
Middle+

O que você sabe sobre as garantias de segurança de exceções?

sobes.tech IA

Resposta da IA

As garantias de segurança de exceções determinam o comportamento de uma função no caso de ocorrer uma exceção. São distinguidos quatro níveis de garantias:

  1. Garantia básica (Basic guarantee): Se a função lançar uma exceção, o programa permanece num estado válido. Os recursos não vazam (por exemplo, a memória é libertada), mas o estado exato dos objetos pode ser desconhecido. Mantém-se a possibilidade de continuar a trabalhar com a aplicação.

    // Exemplo de garantia básica
    void basic_guarantee_function(std::vector<int>& vec, int value) {
        // Podem ocorrer exceções ao inserir
        vec.push_back(value); 
        // Se ocorrer uma exceção, o vec pode estar num estado imprevisível (parcialmente modificado),
        // mas a memória alocada para o vec será libertada corretamente ao sair do escopo.
    } 
    
  2. Garantia forte (Strong guarantee): Se a função lançar uma exceção, o estado do programa mantém-se igual ao que tinha antes da chamada. Todas as alterações são revertidas.

    // Exemplo de garantia forte
    // Uso da idiomática Copy-and-Swap para garantir a garantia forte
    class Resource {
        int* data;
        size_t size;
    public:
        Resource(size_t s) : size(s), data(new int[s]) {}
        ~Resource() { delete[] data; }
        Resource(const Resource& other) : size(other.size), data(new int[other.size]) {
            std::copy(other.data, other.data + size, data); // Pode lançar uma exceção
        }
        Resource& operator=(Resource other) // Transferência por valor que causa cópia
        {
            swap(*this, other); // Não lança exceções
            return *this;
        }
        friend void swap(Resource& first, Resource& second) noexcept {
            using std::swap;
            swap(first.data, second.data);
            swap(first.size, second.size);
        }
        // ... outros membros
    };
    
    void strong_guarantee_function(Resource& res, size_t new_size) {
        Resource temp(new_size); // Se aqui ocorrer uma exceção, res não mudará
        res = temp;               // Usa o operador= sobrecarregado que garante a garantia forte
    }
    
  3. Garantia de não lançar exceções (No-throw guarantee): A função garante que não lançará exceções. Essas funções são marcadas com o especificador noexcept.

    // Exemplo de garantia de não lançar exceções
    void no_throw_function() noexcept {
        // Não há operações que possam lançar exceções
        int a = 5;
        int b = 10;
        int c = a + b;
    }
    
  4. Garantia de falha (Failure guarantee): No contexto de segurança de exceções, às vezes é mencionado este nível, que significa que a função pode deixar o programa num estado indefinido, com possível fuga de recursos ou falhas. Isto é, na realidade, a ausência de garantias. Deve-se evitar tal comportamento.

A importância das garantias de segurança de exceções reside na criação de código fiável e previsível, que trata corretamente erros e recursos mesmo na ocorrência de exceções. A escolha do nível de garantia depende da criticidade da operação, do custo do rollback e da probabilidade de ocorrência de uma exceção.

Tabela comparativa de garantias:

Garantia Estado em caso de exceção Integridade dos dados Fugas de recursos
Básica Válido, mas indefinido Não garantido Não
Forte Não alterado (como antes da chamada) Mantém-se Não
Sem garantias Nunca ocorre (sem exceções) N/A N/A
Falha (sem garantia) Indefinido, possível dano ou falhas Não garantido Possível