Quão importante é inicializar uma variável

9

Quão importante é inicializar variáveis?

A inicialização adequada evita vazamentos de memória ou tem vantagens de desempenho?

Vivek
fonte
14
Depende do idioma. Em alguns idiomas, é muito importante evitar erros; no restante, é apenas uma coisa boa a fazer para ajudar na legibilidade.
Telastyn
Obrigado Telastyn pela sua contribuição. Você pode colocar um caso em que isso se torna importante, dependendo do idioma?
Vivek
4
C ++ é o notório aqui. Na depuração, variáveis ​​locais são inicializadas em 0 (ou null) pelos compiladores comuns, mas são lixo aleatório ao compilar para liberação. (embora meu conhecimento C ++ é de ~ 10 anos atrás, agora, as coisas podem ter mudado)
Telastyn
É um caso de uma vez queimado, duas vezes tímido. Desde que vi / tive bugs causados ​​por variáveis ​​não inicializadas, especialmente indicadores, tornou-se um hábito. Para desempenho, geralmente é irrelevante. Para vazamentos de memória, não é realmente um problema.
precisa saber é o seguinte
11
@Telastyn é pior que isso. O comportamento indefinido não se limita ao estado do lixo, tudo pode acontecer. O compilador pode assumir que os caminhos que lêem variáveis ​​não inicializadas são inacessíveis e eliminam efeitos "não relacionados" que ocorrem ao longo do caminho.
Caleth 18/09/19

Respostas:

7

Variáveis ​​não inicializadas tornam um programa não determinístico. Cada vez que o programa é executado, ele pode se comportar de maneira diferente. Mudanças não relacionadas ao ambiente operacional, hora do dia, fase da lua e permutações de tais afetam como e quando esses daemons se manifestam. O programa pode ser executado um milhão de vezes antes que o defeito seja apresentado, ele pode ser executado toda vez ou executar outro milhão. Muitos problemas são atribuídos a "falhas" e ignorados ou relatórios de defeitos de clientes fechados como "Improdutíveis". Com que frequência você reinicializou uma máquina para 'consertar' um problema? Quantas vezes você disse a um cliente "Nunca vi isso acontecer, deixe-me saber se você o vê novamente" - esperando (sabendo) muito bem que eles não vão!

Como a reprodução de um defeito pode ser quase impossível no ambiente de teste, é quase impossível encontrar e corrigir.

Pode levar anos para que o bug apareça, geralmente no código considerado confiável e estável. Presume-se que o defeito esteja no código mais recente - localizá-lo pode demorar significativamente mais. Uma mudança no compilador, uma opção de compilador, até a adição de uma linha de código pode alterar o comportamento.

A inicialização de variáveis ​​tem uma enorme vantagem de desempenho, não apenas porque um programa que funciona corretamente é infinito mais rápido que um que não funciona, mas os desenvolvedores passam menos tempo localizando e corrigindo defeitos que não deveriam estar lá e mais tempo realizando um trabalho "real".

A outra vantagem significativa de inicializar variáveis ​​é que o autor original do código deve decidir o que inicializar. Isso nem sempre é um exercício trivial e, quando não é trivial, pode ser uma indicação de um design inadequado.

O vazamento de memória é um problema diferente, mas a inicialização adequada pode não apenas ajudar na prevenção, mas também na detecção e localização da fonte - é altamente dependente da linguagem e é realmente uma pergunta separada, digna de uma exploração mais aprofundada do que eu posso dar nesta resposta.

Editar: Em alguns idiomas (por exemplo, C #), não é possível usar variáveis ​​não inicializadas, pois o programa não compila ou relata um erro quando executado, se feito. No entanto, muitas linguagens com essas características possuem interfaces para códigos potencialmente inseguros, portanto, é necessário ter cuidado ao usar essas interfaces no para introduzir variáveis ​​não inicializadas.

mattnz
fonte
6
Muitas linguagens de programação definem automaticamente suas variáveis ​​para algum valor predefinido, muito do que você diz aqui não é aplicável a essas linguagens.
Robert Harvey
2
Apenas para reiterar o que o @RobertHarvey disse, nada disso é aplicável ao C #. Não há vantagem de desempenho em inicializar suas variáveis ​​quando você as declara, e é impossível usar uma variável não inicializada; portanto, você não pode culpar os erros improdutíveis por isso. (Ele é possível usar um campo de classe não inicializada, mas fica definido para um valor padrão e gera um aviso nesse caso)
Bobson
4
@mattnz - O ponto é que, para linguagens que se comportam como C # (ou Java), alguns desses conselhos são enganosos ou totalmente errados. Como uma questão agnóstico linguagem, ele deve ter uma resposta agnósticas idioma, o que significa que aborda as línguas que fazem punho inicializado variáveis com segurança, bem como aqueles que não o fazem.
Bobson
11
Eu também acrescentaria que não é difícil encontrar problemas com variáveis ​​não inicializadas, pois qualquer compilador / analisador estático meio decente os
alertará
11
Para Java (e C #, presumivelmente), a inicialização precoce de locais é desnecessária e, sem dúvida, leva a mais bugs. Por exemplo, definir uma variável como nula antes de atribuí-la condicionalmente anula a capacidade do compilador de informar que um dos caminhos através do código pode não resultar na atribuição da variável.
JimmyJames
7

A inicialização de uma variável como Telastyn apontou pode evitar bugs. Se a variável for um tipo de referência, a inicialização poderá impedir erros de referência nulos na linha.

Uma variável de qualquer tipo que tenha um padrão não nulo ocupará alguma memória para armazenar o valor padrão.

Kevin
fonte
6

Tentar usar uma variável não inicializada é sempre um erro, por isso faz sentido minimizar a probabilidade de ocorrência desse erro.

Provavelmente, a abordagem de linguagem de programação mais comum para atenuar o problema é inicializar automaticamente com um valor padrão; portanto, pelo menos se você esquecer de inicializar uma variável, será algo como, em 0vez de algo como 0x16615c4b.

Isso resolve uma grande porcentagem de erros, se você precisar de uma variável inicializada como zero de qualquer maneira. No entanto, usar uma variável que foi inicializada com um valor incorreto é tão ruim quanto usar uma variável que não foi inicializada. De fato, às vezes pode ser ainda pior, porque o erro pode ser mais sutil e difícil de detectar.

As linguagens de programação funcional resolvem esse problema não apenas desautorizando valores não inicializados, mas desautorizando completamente a reatribuição. Isso elimina o problema e acaba não sendo uma restrição tão severa quanto você imagina. Mesmo em linguagens não funcionais, se você esperar para declarar uma variável até ter um valor correto para inicializá-la, seu código tende a ser muito mais robusto.

Quanto ao desempenho, provavelmente é insignificante. Na pior das hipóteses, com variáveis ​​não inicializadas, você tem uma atribuição extra e amarra alguma memória por mais tempo do que o necessário. Bons compiladores podem otimizar as diferenças em muitos casos.

Vazamentos de memória são completamente independentes, embora as variáveis ​​inicializadas corretamente tendam a estar no escopo por um período mais curto de tempo e, portanto, podem ser um pouco menos propensas a um programador vazar acidentalmente.

Karl Bielefeldt
fonte
Sempre? Você quer dizer que "sempre", como em "Como uma mensagem fixa do Valgrind tornou o OpenSSL quase inútil" marc.info/?t=114651088900003&r=1&w=2 ? Ou você quer dizer o outro, o "quase sempre"?
JensG
11
Eu posso pensar em três idiomas que permitem variáveis ​​não inicializadas sem erro, um dos quais usa para fins lingüísticos.
DougM
Eu estaria interessado nos detalhes. Eu suspeitaria que nesses casos as variáveis ​​não sejam realmente não inicializadas, mas inicializadas de uma maneira que não seja diretamente pelo programador no site da declaração. Ou eles são designados por alguns meios indiretos antes de serem desreferenciados.
Karl Bielefeldt
5

Inicializar implica que o valor inicial é importante. Se o valor inicial importa, então sim, claramente você deve se certificar de que foi inicializado. Se não importa, isso implica que será inicializado mais tarde.

Inicialização desnecessária causa desperdício de ciclos da CPU. Embora esses ciclos desperdiçados possam não ter importância em determinados programas, em outros, cada ciclo é importante, pois a velocidade é a principal preocupação. Portanto, é muito importante entender quais são os objetivos de desempenho e se as variáveis ​​precisam ser inicializadas ou não.

Vazamentos de memória são um problema completamente diferente, que normalmente envolve uma função de alocador de memória para emitir e posteriormente reciclar blocos de memória. Pense em uma agência postal. Você pede uma caixa de correio. Eles te dão um. Você pede outro. Eles te dão outro. A regra é que, quando você terminar de usar uma caixa de correio, precisará devolvê-la. Se você esquecer de devolvê-lo, eles ainda acharão que o possui e a caixa não poderá ser reutilizada por mais ninguém. Portanto, há um pedaço de memória amarrado e não sendo usado, e é isso que é chamado de vazamento de memória. Se você continuar pedindo caixas em algum momento, ficará sem memória. Eu simplifiquei demais isso, mas essa é a ideia básica.

Vista elíptica
fonte
-1 você está redefinindo o que significa inicialização neste contexto.
Pieter B
@ Pieter B, não entendo seu comentário. Por favor, se você quiser, diga como eu estou "redefinindo o que significa inicialização neste contexto". Obrigado
Elliptical view
Leia sua própria frase, é um raciocínio circular: "Inicializar implica que o valor inicial importa. Se o valor inicial importa, então sim, claramente você deve se certificar de que foi inicializado. Se não importa, isso implica que ele será inicializado mais tarde ".
Pieter B
@ Pieter B, Algumas pessoas inicializam como regra geral e não por uma razão programática, isto é, inicializam se o valor inicial é importante ou não. Não é este o coração do OQ: qual a importância de inicializar uma variável? De qualquer forma, você foi votado aqui.
Visualização elíptica
2

Como outros disseram, isso depende do idioma. Mas vou demonstrar minhas idéias Java (e Java efetivo) sobre como inicializar variáveis. Estes devem ser utilizáveis ​​para muitos outros idiomas de nível superior.

Constantes e variáveis ​​de classe

Variáveis ​​de classe - marcadas com staticem Java - são como constantes. Essas variáveis ​​normalmente devem ser finais e inicializadas diretamente após a definição, usando =ou de dentro de um bloco inicializador de classe static { // initialize here }.

Campos

Como em muitos idiomas de nível superior e nos campos de script, será automaticamente atribuído um valor padrão. Para números e chareste será o valor zero. Para Strings e outros objetos, será null. Agora nullé perigoso e deve ser usado com moderação. Portanto, esses campos devem ser configurados com um valor válido o mais rápido possível. O construtor é normalmente um lugar perfeito para isso. Para garantir que as variáveis ​​sejam definidas durante o construtor e não sejam alteradas posteriormente, você pode marcá-las com a finalpalavra - chave

Tente resistir ao desejo de usar nullcomo algum tipo de bandeira ou valor especial. É melhor, por exemplo, incluir um campo específico para manter o estado. Um campo com o nome stateque usa os valores de uma Stateenumeração seria uma boa opção.

Parâmetros do método

Como as alterações nos valores dos parâmetros (sejam referências a objetos ou tipos básicos como números inteiros etc.) não serão vistas pelo chamador, os parâmetros devem ser marcados como final. Isso significa que os valores da variável em si não podem ser alterados. Observe que o valor de instâncias de objetos mutáveis pode ser alterado, a referência não pode ser alterada para apontar para um objeto diferente ou, no nullentanto.

Variáveis ​​locais

Variáveis ​​locais não são inicializadas automaticamente; eles precisam ser inicializados antes que seu valor possa ser usado. Um método para garantir que sua variável seja inicializada é inicializá-la diretamente para algum tipo de valor padrão. No entanto, isso é algo que você não deve fazer. Na maioria das vezes, o valor padrão não é o que você esperaria.

É muito melhor definir apenas a variável exatamente onde você precisa da variável. Se a variável tiver apenas um valor único (o que é verdadeiro para a maioria das variáveis ​​em bom código), você poderá marcar a variável final. Isso garante que a variável local seja atribuída exatamente uma vez, não zero ou duas vezes. Um exemplo:

public static doMethod(final int x) {
    final int y; // no assignment yet, it's final so it *must* be assigned
    if (x < 0) {
        y = 0;
    } else if (x > 0) {
        y = x;
    } else {
        // do nothing <- error, y not assigned if x = 0
        // throwing an exception here is acceptable though
    }
}

Observe que muitos idiomas o alertarão se uma variável permanecer não inicializada antes do uso. Verifique as especificações de idioma e os fóruns para ver se você não se preocupa desnecessariamente.

Maarten Bodewes
fonte
1

Não há problema com variáveis ​​não inicializadas.

O problema é apenas quando você lê uma variável que ainda não foi gravada.

Dependendo do compilador e / ou do tipo de variável, a inicialização é realizada na inicialização do aplicativo. Ou não.

É de uso comum não confiar na inicialização automática.

mouviciel
fonte
0

A inicialização de variáveis ​​(implícita ou explicitamente) é crucial. Não inicializar uma variável é sempre um erro (elas podem ser inicializadas implicitamente, no entanto. Veja abaixo). Compliers modernos como o compilador C # (como exemplo) tratam isso como um erro e não permitem executar o código. Uma variável não inicializada é simplesmente inútil e prejudicial. A menos que você esteja criando um gerador de números aleatórios, você espera que um pedaço de código produza um resultado determinístico e reprodutível. Isso só pode ser alcançado se você começar a trabalhar com variáveis ​​inicializadas.

A questão realmente interessante é se uma variável é inicializada automaticamente ou se você deve fazê-lo manualmente. Depende do idioma usado. Em C #, por exemplo, os campos, ou seja, "variáveis" no nível da classe, são sempre automaticamente inicializados com o valor padrão para esse tipo de variável default(T). Este valor corresponde a um padrão de bits que consiste em todos os zeros. Isso faz parte da especificação da linguagem e não apenas um detalhe técnico da implementação da linguagem. Portanto, você pode confiar nele com segurança. É seguro não inicializar uma variável explicitamente se (e somente se) a especificação da linguagem declarar que foi inicializada implicitamente.Se você deseja outro valor, deve inicializar a variável explicitamente. Contudo; em C # variáveis ​​locais, ou seja, variáveis ​​declaradas em métodos, não são inicializadas automaticamente e você sempre deve inicializar a variável explicitamente.

Olivier Jacot-Descombes
fonte
2
essa não é uma pergunta específica do C #.
DougM
@ DougM: Eu sei. Não é uma resposta específica de C #, apenas tomei C # como exemplo.
Olivier Jacot-Descombes
Nem todos os idiomas exigem que as variáveis ​​sejam explicitamente inicializadas. Sua declaração "não inicializar sempre é um erro" é falsa e não adiciona nenhuma clareza à pergunta em questão. você pode revisar sua resposta.
DougM
@ DougM: Você supervisionou minha frase "A questão realmente interessante é se uma variável é inicializada automaticamente ou se você deve fazê-lo manualmente."?
Olivier Jacot-Descombes
você quer dizer o que está enterrado no meio do parágrafo? sim. Você deveria torná-lo mais proeminente e adicionar um qualificador à sua reivindicação "sempre".
DougM