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.
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:
- O construtor
TZQuery.Createcomeça a ser executado para alocar memória. - Por algum motivo (como falta de memória no sistema ou falha na inicialização interna do componente), o método
Createlança uma **exceção**. - A variável
qryfica com um valor indefinido (lixo de memória) ounil, pois a atribuiçãoqry := ...**não foi concluída**. - Como o
Createestava dentro do blocotry, a exceção força o fluxo da aplicação a pular **imediatamente** para o blocofinally. - O bloco
finallytenta executarqry.Freeem uma variável que aponta para um ponteiro inválido ou não inicializado.
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
.Createfalhar: O fluxo nem sequer entra no blocotry. A exceção é capturada pela aplicação sem passar pelofinally, evitando tentar liberar algo que não existe. -
Se o
.Createfor bem-sucedido: O objetoqryestará validado na memória. Em seguida, o fluxo entra no blocotrye, ocorrendo erro ou não nas operações seguintes (como conectar ao banco ou executar SQL), ofinallygarantirá oqry.Freecom 100% de segurança.
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