Fala Pessoal, tudo bem com vocês?
Hoje vim aqui falar um pouquinho sobre as variáveis gerenciáveis (ou managed variables) e não-gerenciáveis do Delphi. Você já ouviu falar sobre esse termo? Eu, particularmente, me deparei sobre esse assunto apenas na semana passada, quando estava estudando sobre outro assunto, e por isso resolvi trazer aqui pra vocês uma breve explicação do que são as variáveis gerenciáveis no Delphi. Vem comigo que eu vou te mostrar!
Antes de entendermos o que são as variáveis gerenciáveis e qual a diferença delas para as não-gerenciáveis precisamos responder algumas perguntas…
O que são as “variáveis”?
Uma variável é uma posição de memória do computador, cuja finalidade é armazenar dados em um programa durante um determinado espaço de tempo. Ou seja:
Quando declaramos uma variável o que estamos fazendo é alocar um espaço na memória do computador. Elas funcionam como containers para dados e seus tipos dizem ao compilador como interpretar os valores que elas estão armazenando.
Através de uma variável você pode ler e escrever nesse espaço de memória. Em nosso código-fonte, as variáveis são representadas por identificadores (identifiers) cujo valor pode ser alterado em tempo de execução.
Abaixo um exemplo da declaração de algumas variáveis:
var i, j: Integer; s: string; o: TObject;
O espaço de memória alocado por uma variável é liberado (ou pelo menos deveria ser) quando ela não estiver mais sendo usada, e esse “tempo de vida” irá depender basicamente do seu escopo. As variáveis locais, por exemplo, somente existem até que a execução do programa saia da função ou procedure da qual elas foram declaradas.
E o que é “escopo de uma variável”?
De acordo com o dicionário, a palavra escopo significa “espaço ou oportunidade para um movimento, atividade ou pensamento desimpedido”, no âmbito da declaração de variáveis o seu escopo é definido pelo local onde a mesma foi declarada, podendo ser Local ou Global.
Quando declaramos uma variável dentro de uma procedure ou de uma função dizemos que essas são variáveis locais, quando elas são declaradas em outros pontos do código dizemos que elas são variáveis globais.
As variáveis globais podem ser inicializadas juntamente com sua declaração, já o mesmo não pode ser feito com as variáveis locais. Veja, no exemplo abaixo, a declaração da variável i fará com que ela já seja inicializada com o valor 15, porém a declaração da variável j irá gerar um erro de compilação.
var i: Integer = 15; procedure ExemploVariavelLocal; var j: Integer = 15; begin // Algum código aqui end;
Caso você não defina um valor inicial para as variáveis globais, elas serão automaticamente inicializadas pelo compilador com zero. Já as variáveis locais têm seu valor indefinido (o famoso lixo de memória) até que você defina um valor para elas. Neste caso, a única exceção são os tipos de variáveis gerenciáveis, pois estas, mesmo declaradas localmente, serão inicializadas.
Neste artigo eu explico e exemplifico com mais detalhes sobre as inicializações das variáveis.
Mas, afinal, o que são variáveis gerenciáveis?
As variáveis gerenciáveis são aquelas em que o Delphi adiciona alguns códigos “por trás dos panos” para controlar a sua inicialização, limpeza e atribuição e elas têm, explícita ou implicitamente, um contador de referência.
Para entendermos melhor como isso acontece, vamos considerar o exemplo abaixo:
type TFoo = record I: Integer; S: string; end; procedure TesteVariaveisLocais(const Condicao: Boolean); var S: string; I: IInterface; F: TFoo; begin if Condicao then begin S := 'Local String'; I := TInterfacedObject.Create; F.S := 'Managed Record'; end; end;
Nesse exemplo utilizamos três variáveis locais que são gerenciáveis. isso quer dizer que, mesmo elas sendo locais, elas serão inicializadas e finalizadas pelo compilador, que irá gerar um código da seguinte maneira:
procedure TesteVariaveisLocais(const Condicao: Boolean); var S: string; I: IInterface; F: TFoo; begin S := nil; // Adicionado pelo compilador I := nil; // Adicionado pelo compilador InitializeRecord(F); // Adicionado pelo compilador if Condicao then begin S := 'Local String'; I := TInterfacedObject.Create; F.S := 'Managed Record'; end; FinalizeRecord(F); // Adicionado pelo compilador IntfClear(I); // Adicionado pelo compilador UStrClr(S); // Adicionado pelo compilador end;
Veja que, internamente, o compilador adicionou ao código a inicialização e finalização das variáveis. Isso porque elas fazem parte dos tipos de variáveis gerenciáveis.
São exemplos de variáveis gerenciáveis as
string
, dynamic arrays
, variants
, e interfaces
. Além disso, os records que possuírem pelo menos um campo desse tipo, também serão gerenciáveis. Neste caso, tanto o InitializeRecord
quanto o FinalizeRecord
irá percorrer todos os campos do record, recursivamente, para inicializá-los e finalizá-los, respectivamente.Os demais tipos, são não-gerenciáveis, ou porque não precisam de gerenciamento, como é o caso dos tipos ordinais, por exemplo, que tem o tempo de vida até a variável não estejam mais sendo utilizadas, ou por serem objetos mais complexos na qual ficará a cargo do programador controlar sua inicialização e finalização.
Como em Delphi, os tipos de variáveis gerenciáveis são definidos pelo código gerado pelo compilador, podemos dizer que elas são específicas da linguagem. Já que em outras linguagens, como o .Net, por exemplo, o programador não precisa se preocupar com o tempo de vida das variáveis, pois ele possui um mecanismo que já faz isso por nós: o chamado Garbage Collector.
Autor: Flávia Melo
Postar um comentário