Pergunta

A afirmação é usada para verificar se uma condição é atendida (pré -condição, pós -condição, invariantes) e ajudar os programadores a encontrar orifícios durante a fase de depuração.

Por exemplo,

void f(int *p)
{
  assert(p);
  p->do();
}

Minha pergunta é: precisamos assumir que a condição não poderia ser atendida no modo de liberação e lidar com o caso de acordo?

void f(int *p)
{
  assert(p);

  if (p)
  {
    p->do();
  }
}

Afinal, afirmação significa que a condição que testes nunca deve ser falsa. Mas se, se não verificarmos e falhar, travará o programa. Parece um dilema. Como vocês lidam com isso?

Foi útil?

Solução

Se a afirmação falhar, O programa deve travar.

Uma falha de afirmação significa que o programador cometeu um erro fundamental em sua compreensão de como é possível que o fluxo do programa prossiga. Este é um auxílio ao desenvolvimento, não um auxílio de produção. Na produção, pode -se lidar exceções, como eles "podem" ocorrer, enquanto as afirmações "nunca devem" falhar.

Se você está no acampamento que diz: "Oh, mas e se as afirmações falharem na produção? Preciso pegá -las!" Então você está perdendo o ponto. Pergunte a si mesmo, nesse caso, Por que você não está apenas jogando uma exceção (ou lidando com o erro)?

De um modo geral, afirmar é não Apenas uma abreviação de "Se a condição não atendida, jogue exceção" (bem, às vezes essa é a semântica operacional, mas não é a semântica denotacional). Em vez disso, uma falha de afirmação significa que o aplicativo está em um estado que o desenvolvedor não acredita ser nem mesmo possível. Você realmente quer que o código continue executando nesse caso? Claramente (eu diria), Não.

Outras dicas

A programação defensiva é sempre melhor. Você sempre deve assumir que, apesar de todos os seus testes, seu aplicativo será enviado com bugs. Como tal, é do seu interesse adicionar verificações nulas em situações em que você pode evitar uma deferência nula de ponteiro e simplesmente seguir em frente.

No entanto, existem situações em que simplesmente não há maneira fácil de evitar um acidente e, nesses casos, a afirmação é sua única maneira de detectar o problema durante o seu ciclo de desenvolvimento.

Um ponto importante, porém - afirma também ser usado frequentemente para detectar grandes problemas com a integridade de seus dados. Se você continuar além dessas afirmações, poderá correr o risco de corromper dados. Nesses casos, pode ser melhor travar do que destruir seus dados. (Obviamente, qualquer tipo de manipulador de colisão que pelo menos traz uma interface do usuário razoável com uma descrição de erro seria preferível).

Estritamente falando, o segundo código tem redundância.

void f(int *p)
{
  assert(p);
  if (p)    // Beats the purpose of assertion
  {
    p->do();
  }
}

ASSERÇÃO significa que o erro ocorreu. Algo que é inesperado/não tratado. No código acima, seja

1) Você está lidando adequadamente com o caso em que P é nulo. (por não ligar para p-> fazer ())- que supostamente é a coisa certa/esperada a fazer. No entanto, então a afirmação é um Alarme falso.

2) Por outro lado, se por não chamar p-> do (), algo dará errado (talvez mais no código ou na saída), a afirmação está certa, mas não deve haver sentido em continuar de qualquer maneira.

No código acima, o programador está trabalhando muito para lidar com casos errôneos de qualquer maneira.

Dito isto, algumas pessoas gostam de tratar as afirmações como Algo deu errado, mas vamos ver se ainda obtemos saída correta. IMO, isso é uma estratégia ruim e cria confusões durante a correção de bugs.

As afirmações estão depurando o código, não o código de operação. Não os use para capturar erros de entrada.

As afirmações são usadas para capturar bugs nos testes. A teoria é que você testou bem o suficiente para saber que funcionará assim que você o lançar.

Se houver alguma possibilidade de que a condição possa surgir na operação da vida real, não confie em afirmações - use exceções ou algum outro mecanismo de erro.

As afirmam que são úteis para depuração como você mencionou. Eles nunca devem entrar no código de produção (como compilado, não há problema em envolvê -los em #ifdefs, é claro)

Se você está enfrentando um problema em que está além do seu controle para corrigir e precisará da verificação do seu código de produção, farei algo como:

void f(int *p)
{

  if (!p)
  {
    do_error("FATAL, P is null.");
  }

  p->do();
}

Onde o do_error é uma função que registra um erro e sai de forma limpa.

Eu digo que deixe -os na construção de lançamento. Deve haver bugs em qualquer compilação. Ter afirmado em seu produto significa que você pode identificar o problema mais facilmente quando recebe o relatório de problemas da à Uwer.

Não faça muito esforço para lidar com as exceções. Simplesmente verifique se você pode se apossar da exceção completa, incluindo o StackTrace. Isso se aplica à versão à versão em particular.

Como muitas pessoas estão comentando sobre a colocação de afirmações no modo de liberação:

No que trabalho, a eficiência é muito importante (às vezes, a execução em grandes conjuntos de dados leva dezenas de horas a alguns dias para ser concluída). Portanto, temos macros especiais que afirmam apenas no código de depuração (executado durante o controle de qualidade etc). Como exemplo, uma afirmação dentro de um loop é definitivamente uma sobrecarga e você pode evitá -lo no código de liberação. Afinal, se tudo bem, as afirmam que não devem falhar.

Um exemplo em que o código de liberação afirma ser bom é - se a lógica não deve atingir uma filial específica do código. Nesse caso, o afirmador (0) é bom [portanto, qualquer tipo de afirmação (0) sempre pode ser deixado no código de liberação].

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top