As variáveis ​​delphi são inicializadas com um valor por padrão?

103

Eu sou novo no Delphi, e tenho executado alguns testes para ver quais variáveis ​​de objeto e variáveis ​​de pilha são inicializadas por padrão:

TInstanceVariables = class
  fBoolean: boolean; // always starts off as false
  fInteger: integer; // always starts off as zero
  fObject: TObject; // always starts off as nil
end;

Este é o comportamento que estou acostumado em outras linguagens, mas estou me perguntando se é seguro confiar nele no Delphi? Por exemplo, estou me perguntando se isso pode depender de uma configuração do compilador ou talvez funcionar de forma diferente em máquinas diferentes. É normal confiar em valores inicializados padrão para objetos ou você define explicitamente todas as variáveis ​​de instância no construtor?

Quanto às variáveis ​​da pilha (nível de procedimento), meus testes estão mostrando que os booleanos unitializados são verdadeiros, os inteiros unitializados são 2129993264 e os objetos não inicializados são apenas ponteiros inválidos (ou seja, não nulo). Estou supondo que a norma é sempre definir variáveis ​​de nível de procedimento antes de acessá-los.

MB.
fonte
3
Duas notas: 1. Os registros não são inicializados. 2. Variáveis ​​contadas de referência são sempre inicializadas. !MAS! em uma função que retorna uma string, 'Result' não é inicializado para uma string vazia como você pode esperar. Isso ocorre porque 'Result' não é uma var local. Portanto, sempre faça: Result: = '';
InTheNameOfScience
Isso responde sua pergunta? Quais variáveis ​​são inicializadas no Delphi?
InTheNameOfScience

Respostas:

105

Sim, este é o comportamento documentado:

  • Os campos de objeto são sempre inicializados com 0, 0,0, '', False, nil ou o que for aplicável.

  • Variáveis ​​globais são sempre inicializadas com 0 etc também;

  • Variáveis ​​contadas por referência local * são sempre inicializadas com nil ou '';

  • Variáveis ​​locais não contadas por referência * não são inicializadas, portanto, você deve atribuir um valor antes de usá-las.

Lembro-me de que Barry Kelly em algum lugar escreveu uma definição para "contagem de referência", mas não consigo mais encontrá-la, então isso deve servir enquanto isso:

contados por referência == que são contados por referência próprios, ou direta ou indiretamente contêm campos (para registros) ou elementos (para matrizes) que são contados por referência como: string, variant, interface ou matriz dinâmica ou matriz estática contendo tais tipos.

Notas:

  • record em si não é suficiente para se tornar contado por referência
  • Eu não tentei isso com genéricos ainda
Giacomo Degli Esposti
fonte
2
Como Giacomo apontou nos comentários abaixo, tudo isso é explicado nos arquivos de ajuda do Delphi em ms-help: //borland.bds4/bds4ref/html/Variables.htm. No Delphi 2009 encontrei a mesma informação pesquisando a ajuda por "variáveis" (curiosamente, tentei muitas pesquisas, mas não pensei em tentar essa).
MB.
8
Variáveis ​​locais SÃO inicializadas ($ 0) se forem de um tipo gerenciado como strings, interfaces, matrizes dinâmicas ou variantes
Francesca
5
Porém, há uma exceção! Quando você sobrescreve o construtor e não chama o construtor herdado, há uma chance de que alguns campos terminem não inicializados! (Especialmente com versões mais antigas do Delphi.) Uma vez que TObject.Create é responsável por zerar todos os dados, não chamar aquele resulta em possíveis dados desconhecidos.
Wim ten Brink
18
@WimtenBrink Acho que você está errado. A inicialização não é feita dentro TObject.Create, que é um método void, mas no class function TObject.InitInstance(Instance: Pointer): TObject;qual é SEMPRE chamado antes de qualquer chamada do construtor, mesmo para versões mais antigas do Delphi. Seu comentário é IMHO errado e confuso.
Arnaud Bouchez
7
Não se esqueça de que em uma função que retorna uma string, 'Result' não é inicializado como uma string vazia como você pode esperar. Isso ocorre porque 'Result' não é uma var local.
InTheNameOfScience
27

Variáveis ​​globais que não possuem um inicializador explícito são alocadas na seção BSS do executável. Na verdade, eles não ocupam nenhum espaço no EXE; a seção BSS é uma seção especial que o sistema operacional aloca e limpa para zero. Em outros sistemas operacionais, existem mecanismos semelhantes.

Você pode depender de variáveis ​​globais sendo inicializadas com zero.

Barry Kelly
fonte
21

Os campos de classe são o padrão zero. Isso está documentado para que você possa confiar nele. As variáveis ​​da pilha local são indefinidas, a menos que string ou interface sejam definidas como zero.

Martin Liesén
fonte
Obrigado. "Zero" está me confundindo um pouco - isso significa que as strings são '' e as interfaces são nulas?
MB.
4
Sim, exatamente isso. nil = 0 (no nível do assembler) e '' = nil (convenção Delphi).
gabr
1
"a menos que string ou interface" não seja uma descrição completa da realidade. Arrays dinâmicos, por exemplo, também são inicializados. De forma mais geral, a regra é que as variáveis ​​de tipos gerenciados (contados por referência) são inicializadas, mesmo se locais.
Andreas Rejbrand
16

Apenas como uma observação lateral (já que você é novo no Delphi): Variáveis ​​globais podem ser inicializadas diretamente ao serem declaradas:

var myGlobal:integer=99;
Heinrich Ulbricht
fonte
2
Desde 10.3, o mesmo se aplica a variáveis ​​locais
Edijs Kolesnikovičs de
1
E se não for feito explicitamente, eles são inicializados como 0, 0.0, False, nil, [], etc.
Andreas Rejbrand
7

Aqui está uma citação de Ray Lischners Delphi in a Nutshell Capítulo 2

"Quando o Delphi cria um objeto pela primeira vez, todos os campos começam vazios, ou seja, os ponteiros são inicializados com nil, strings e arrays dinâmicos estão vazios, os números têm o valor zero, os campos booleanos são falsos e as variantes são definidas como não atribuídas. (Consulte NewInstance e InitInstance no Capítulo 5 para obter detalhes.) "

É verdade que variáveis ​​locais no escopo precisam ser inicializadas ... Eu trataria o comentário acima de que "Variáveis ​​globais são inicializadas" como duvidoso até que seja fornecido com uma referência - eu não acredito nisso.

editar ... Barry Kelly diz que você pode contar com eles sendo inicializados em zero, e como ele está na equipe de compiladores do Delphi, acredito que isso se mantém :) Obrigado Barry.

Drew Gibson
fonte
1
Na ajuda do delphi 2006, você pode encontrá-lo aqui: ms-help: //borland.bds4/bds4ref/html/Variables.htm "Se você não inicializar explicitamente uma variável global, o compilador a inicializa com 0. Dados da instância do objeto ( campos) também são inicializados com 0. "
Giacomo Degli Esposti
Votos negativos por causa de "Eu não acredito nisso". Isso é programação, não religião. E Giacomo apenas demonstrou a verdade.
InTheNameOfScience
6

Variáveis ​​globais e dados de instância de objeto (campos) são sempre inicializados com zero. Variáveis ​​locais em procedimentos e métodos não são inicializados no Win32 Delphi; seu conteúdo é indefinido até que você atribua a eles um valor no código.

Ondrej Kelle
fonte
5

Mesmo que um idioma ofereça inicializações padrão, não acredito que você deva confiar neles. A inicialização com um valor torna isso muito mais claro para outros desenvolvedores que podem não saber sobre inicializações padrão na linguagem e evita problemas entre compiladores.

Thomas Owens
fonte
4
Claro que você pode. E você deve. Inicializar tudo para 0 / '' / false / nil em cada construtor é simplesmente desnecessário. Inicializar variáveis ​​globais, por outro lado, não é tão estúpido - pela primeira vez, nunca consigo me lembrar se elas foram inicializadas ou não (já que não as estou usando muito).
gabr
2
Se o Delphi permitir que você inicialize uma variável no mesmo ponto em que você a declara (por exemplo, var fObject: TObject = nil), estaria inclinado a concordar que inicializar para um valor é provavelmente uma boa ideia. Mas para mim parece um pouco demais fazer isso no construtor para cada campo de objeto.
MB.
4

Do arquivo de ajuda do Delphi 2007:

ms-help: //borland.bds5/devcommon/variables_xml.html

"Se você não inicializar explicitamente uma variável global, o compilador a inicializa com 0."

Ondrej Kelle
fonte
3

Eu tenho uma pequena reclamação com as respostas dadas. Delphi zera o espaço de memória dos globais e dos objetos recém-criados. Embora isso NORMALMENTE signifique que eles foram inicializados, há um caso em que eles não são: tipos enumerados com valores específicos. E se zero não for um valor legal ??

Loren Pechtel
fonte
1
Zero é sempre um valor legal, é o primeiro valor do enum. você pode vê-lo com ord (MyFirstEnumValue).
Francesca,
Ele retornaria o primeiro valor do tipo enumerado.
skamradt
6
Zero nem sempre é um valor legal se você atribuir explicitamente valores ao enum. Nesse caso, ele ainda é inicializado com 0 e você tem um valor ilegal. Mas enums são apenas açúcar sintático pintado sobre tipos inteiros normais, então isso realmente não quebra nada. Certifique-se de que seu código pode lidar com isso.
Mason Wheeler
2
@ François: Não se você definir seu enum assim:TOneTwoThree = (One=1, Two=2, Three=3);
fnkr
0

As variáveis ​​inline recentemente introduzidas (desde o Delphi 10.3) estão tornando o controle dos valores iniciais mais fácil.

procedure TestInlineVariable;
begin
  var index: Integer := 345;
  ShowMessage(index.ToString);
end;
Jacek Krawczyk
fonte