sexta-feira, 2 de outubro de 2026

Porque o Create é Fora do Try/Finally

Se você programa em Object Pascal (Delphi / Lazarus), com certeza já viu esse padrão de código:

qry := TZQuery.Create(nil);
try
  qry.Connection := ObterConexao;
  // operações no banco de dados...
finally
  qry.Free;
end;

Uma dúvida muito comum de quem está começando — e até de desenvolvedores mais experientes — é: "Por que a instanciação TZQuery.Create(...) é feita antes da instrução try e não dentro dela?"

A resposta envolve o funcionamento da gestão de memória e o tratamento de exceções no Pascal.

1. A Regra de Ouro do bloco try/finally

O objetivo da instrução try...finally é garantir a liberação de recursos (executando o bloco finally), independentemente de ter ocorrido uma exceção ou não dentro do bloco try.

💡 Princípio Fundamental:
Você só deve tentar liberar um recurso no bloco finally se esse recurso foi **efetivamente e com sucesso alocado** antes de entrar no bloco.

2. O que acontece se colocarmos o `.Create` DENTRO do `try`?

Considere a versão **incorreta** do código abaixo:

// ❌ CÓDIGO INCORRETO - EVITE ISSO!
try
  qry := TZQuery.Create(nil); // E se isto falhar?
  qry.Connection := ObterConexao;
finally
  qry.Free;
end;

Agora imagine o seguinte cenário de erro durante o processo de instanciação:

  1. O construtor TZQuery.Create começa a ser executado para alocar memória.
  2. Por algum motivo (como falta de memória no sistema ou falha na inicialização interna do componente), o método Create lança uma **exceção**.
  3. A variável qry fica com um valor indefinido (lixo de memória) ou nil, pois a atribuição qry := ... **não foi concluída**.
  4. Como o Create estava dentro do bloco try, a exceção força o fluxo da aplicação a pular **imediatamente** para o bloco finally.
  5. O bloco finally tenta executar qry.Free em uma variável que aponta para um ponteiro inválido ou não inicializado.
🔥 O Resultado: Access Violation!
Ao tentar executar qry.Free em um objeto que falhou ao ser criado, o sistema pode disparar um erro catastrófico de Access Violation (Violação de Acesso), mascarando o erro original da criação e tornando a depuração do problema muito mais difícil.

3. A Forma Correta e Segura

Ao manter o Create fora do bloco try, garantimos um fluxo limpo e robusto:

//  CÓDIGO CORRETO E SEGURO
qry := TZQuery.Create(nil);
try
  qry.Connection := ObterConexao;
  // Se ocorrer um erro aqui, a query já existe!
  // O finally vai destruí-la com segurança.
finally
  qry.Free;
end;

O que muda nesse cenário?

  • Se o .Create falhar: O fluxo nem sequer entra no bloco try. A exceção é capturada pela aplicação sem passar pelo finally, evitando tentar liberar algo que não existe.
  • Se o .Create for bem-sucedido: O objeto qry estará validado na memória. Em seguida, o fluxo entra no bloco try e, ocorrendo erro ou não nas operações seguintes (como conectar ao banco ou executar SQL), o finally garantirá o qry.Free com 100% de segurança.
📌 Dica sobre `Free` vs `FreeAndNil`:
O método .Free interno das classes do Delphi verifica se a referência é diferente de nil antes de chamar o destruidor. Portanto, chamar qry.Free é completamente seguro, desde que o objeto tenha sido devidamente instanciado.

Conclusão

Esta é uma boa prática para **qualquer objeto em Pascal** (e em várias outras linguagens com gerenciamento manual ou por blocos try/finally).

A regra simples para memorizar no seu dia a dia é: Aloque antes do try, proteja no try e libere no finally!

Nenhum comentário:

Postar um comentário