Quanto è importante inizializzare una variabile


9

Quanto è importante inizializzare le variabili?

Una corretta inizializzazione evita perdite di memoria o presenta vantaggi in termini di prestazioni?


14
Dipende dalla lingua. In alcune lingue è abbastanza importante prevenire i bug, nel resto è semplicemente una buona cosa da fare per aiutare la leggibilità.
Telastyn,

Grazie Telastyn per il tuo contributo. Puoi mettere un caso in cui diventa importante a seconda della lingua?
Vivek,

4
Il C ++ è il famigerato qui. Nel debug, le variabili locali sono inizializzate su 0 (o null) dai compilatori comuni, ma sono spazzatura casuale durante la compilazione per il rilascio. (anche se la mia conoscenza del C ++ è di circa 10 anni fa, le cose potrebbero essere cambiate)
Telastyn,

È un caso di una volta bruciato due volte timido. Da quando ho visto / avuto bug causati da variabili non inizializzate, in particolare i puntatori, è diventata un'abitudine. Per le prestazioni, di solito è irrilevante. Per perdite di memoria, non è un problema.
Mike Dunlavey,

1
@Telastyn è peggio di così. Il comportamento indefinito non si limita allo stato di immondizia, tutto può succedere. Il compilatore può presumere che i percorsi che leggono variabili non inizializzate siano irraggiungibili ed elimini gli effetti "non correlati" che si verificano lungo la strada.
Caleth,

Risposte:


7

Le variabili non inizializzate rendono un programma non deterministico. Ogni volta che il programma viene eseguito, potrebbe comportarsi diversamente. Cambiamenti non correlati all'ambiente operativo, all'ora del giorno, alla fase della luna e alle permutazioni di tali effetti influenzano come e quando questi demoni si manifestano. Il programma può essere eseguito un milione di volte prima che si presenti il ​​difetto, possono farlo ogni volta o eseguire un altro milione. Molti problemi sono ricondotti a "anomalie" e ignorati, o segnalazioni di difetti da parte di clienti chiusi come "Non riproducibili". Con quale frequenza hai riavviato un computer per "risolvere" un problema? Quante volte hai detto a un cliente "Non l'ho mai visto accadere, fammi sapere se lo vedi di nuovo" - sperando (sapendo) bene che non lo faranno!

Poiché la riproduzione di un difetto può essere quasi impossibile nell'ambiente di prova, è quasi impossibile da trovare e correggere.

Possono volerci anni per far emergere il bug, comunemente nel codice ritenuto affidabile e stabile. Si presume che il difetto sia nel codice più recente: rintracciarlo può richiedere molto più tempo. Una modifica nel compilatore, uno switch del compilatore, anche l'aggiunta di una riga di codice può cambiare il comportamento.

L'inizializzazione delle variabili ha un enorme vantaggio in termini di prestazioni, non solo perché un programma che funziona correttamente è infinitamente più veloce di uno che non lo fa, ma gli sviluppatori impiegano meno tempo a trovare e correggere difetti che non dovrebbero esserci e più tempo a fare un lavoro "reale".

L'altro vantaggio significativo dell'inizializzazione delle variabili è che l'autore originale del codice deve decidere a cosa inizializzarle. Questo non è sempre un esercizio banale e, se non banale, può essere un'indicazione di un design scadente.

Le perdite di memoria sono un problema diverso, ma una corretta inizializzazione può non solo aiutare a prevenirle, ma può anche aiutare a rilevarle e trovare la fonte - è altamente dipendente dalla lingua e questa è davvero una domanda separata degna di ulteriori esplorazioni di quelle che sono in grado di dare in questa risposta.

Modifica: in alcune lingue (ad es. C #) non è possibile utilizzare variabili non inizializzate, poiché il programma non verrà compilato o, se eseguito, verrà segnalato un errore quando eseguito. Tuttavia, molte lingue con queste caratteristiche hanno interfacce per codici potenzialmente non sicuri, quindi bisogna usare cautela quando si usano tali interfacce per introdurre variabili non inizializzate.


6
Molti linguaggi di programmazione impostano automaticamente le loro variabili su un valore predefinito, quindi gran parte di ciò che dici qui non è applicabile a quei linguaggi.
Robert Harvey,

2
Solo per ribadire quanto affermato da @RobertHarvey, nulla di tutto ciò è applicabile a C #. Non c'è alcun vantaggio in termini di prestazioni nell'inizializzare le variabili quando le dichiari, ed è impossibile usare una variabile non inizializzata, quindi non puoi dare la colpa a bug non riproducibili. (Si è possibile utilizzare un campo di classe non inizializzata, ma ottiene impostato su un valore predefinito e genera un avviso in questo caso)
Bobson

4
@mattnz - Il punto è che per i linguaggi che si comportano come C # (o Java), alcuni di questi consigli sono fuorvianti o assolutamente sbagliati. Come linguaggio domanda agnostica, si dovrebbe avere una risposta agnostica lingua, il che significa che affrontano lingue che fanno variabili maniglia inizializzato in modo sicuro così come quelli che non lo fanno.
Bobson,

1
Aggiungo anche che il problema con le variabili non inizializzate non è difficile da trovare poiché qualsiasi compilatore / analizzatore statico decente lo avvertirà
jk.

1
Per Java (e presumibilmente C #) l'inizializzazione prematura dei locali non è necessaria e probabilmente porta a più bug. Ad esempio, impostare una variabile su null prima di assegnarla condiziona in modo condizionale la capacità del compilatore di dirti che uno dei percorsi attraverso il codice potrebbe non comportare l'assegnazione della variabile.
JimmyJames,

7

L'inizializzazione di una variabile come sottolineato da Telastyn può prevenire i bug. Se la variabile è un tipo di riferimento, l'inizializzazione può impedire errori di riferimento null lungo la linea.

Una variabile di qualsiasi tipo che ha un valore predefinito non nullo occuperà un po 'di memoria per memorizzare il valore predefinito.


6

Cercare di utilizzare una variabile non inizializzata è sempre un bug, quindi ha senso ridurre al minimo la probabilità che si verifichi quel bug.

Probabilmente l'approccio più comune adottato dai linguaggi di programmazione per mitigare il problema è l'inizializzazione automatica su un valore predefinito, quindi almeno se si dimentica di inizializzare una variabile, sarà qualcosa di simile 0invece di qualcosa di simile 0x16615c4b.

Questo risolve una grande percentuale di bug, se ti è capitato di aver bisogno di una variabile inizializzata a zero comunque. Tuttavia, l'utilizzo di una variabile inizializzata su un valore errato è altrettanto grave dell'uso di una variabile che non è stata affatto inizializzata. In effetti, a volte può essere anche peggio, perché l'errore può essere più sottile e difficile da rilevare.

I linguaggi di programmazione funzionale risolvono questo problema non solo impedendo i valori non inizializzati, ma impedendo del tutto la riassegnazione. Ciò elimina il problema e risulta non essere una restrizione così grave come si potrebbe pensare. Anche in linguaggi non funzionali, se aspetti di dichiarare una variabile fino a quando non hai un valore corretto per inizializzarla, il tuo codice tende ad essere molto più robusto.

Per quanto riguarda le prestazioni, è probabilmente trascurabile. Nel peggiore dei casi con variabili non inizializzate, hai un compito in più e legami un po 'di memoria più a lungo del necessario. Buoni compilatori possono ottimizzare le differenze in molti casi.

Le perdite di memoria sono completamente indipendenti, sebbene le variabili correttamente inizializzate tendano ad avere una portata per un periodo di tempo più breve, e quindi potrebbe essere un po 'meno probabile che un programmatore perda accidentalmente.


Sempre? Vuoi dire che "sempre" come in "Come un messaggio Valgrind fisso ha reso OpenSSL vicino inutile" marc.info/?t=114651088900003&r=1&w=2 ? O intendi l'altro, quello "quasi sempre"?
JensG,

1
Sono in grado di pensare a tre lingue che consentono variabili non inizializzate senza errori, una delle quali utilizza tali per uno scopo linguistico.
DougM,

Sarei interessato ai dettagli. Sospetto in quei casi che le variabili non sono veramente non inizializzate, ma sono inizializzate in un modo diverso da quello direttamente dal programmatore nel sito della dichiarazione. Oppure sono assegnati in modo indiretto prima di essere sottoposti a dereferenziazione.
Karl Bielefeldt,

5

L'inizializzazione implica che il valore iniziale è importante. Se il valore iniziale è importante, quindi sì, è necessario assicurarsi che sia inizializzato. Se non importa, ciò implica che verrà inizializzato in seguito.

L'inizializzazione non necessaria provoca sprechi cicli della CPU. Mentre questi cicli sprecati potrebbero non avere importanza in alcuni programmi, in altri programmi, ogni singolo ciclo è importante poiché la velocità è di primaria importanza. Quindi è molto importante capire quali sono i propri obiettivi di performance e se le variabili devono essere inizializzate o meno.

Le perdite di memoria sono un problema completamente diverso che in genere comporta una funzione di allocatore di memoria per emettere e successivamente riciclare blocchi di memoria. Pensa a un ufficio postale. Vai a chiedere una cassetta postale. Ti danno uno. Ne chiedi un altro. Ti danno un altro. La regola è che quando hai finito di usare una casella di posta che devi restituire. Se dimentichi di restituirlo, pensano ancora di averlo e la scatola non può essere riutilizzata da nessun altro. Quindi c'è un pezzo di memoria legato e non utilizzato, e questo è ciò che viene chiamato perdita di memoria. Se continui a chiedere caselle a un certo punto, rimarrai senza memoria. L'ho semplificato troppo, ma questa è l'idea di base.


-1 stai ridefinendo il significato dell'inizializzazione in questo contesto.
Pieter B,

@Pieter B, non capisco il tuo commento. Per favore, se vuoi, dì come sto "ridefinendo il significato dell'inizializzazione in questo contesto". Grazie
Vista ellittica

Leggi la tua frase, è un ragionamento circolare: "Inizializzazione, implica che il valore iniziale è importante. Se il valore iniziale è importante, quindi sì, chiaramente devi assicurarti che sia inizializzato. Se non importa, ciò implica che otterrà inizializzato più tardi. "
Pieter B,

@Pieter B, Alcune persone si inizializzano come una regola generale piuttosto che per un motivo programmatico, cioè inizializzano se il valore iniziale è importante o meno. Non è questo il cuore di OQ: quanto è importante inizializzare una variabile? Ad ogni modo, sei stato votato qui.
Vista ellittica

2

Come altri hanno detto, dipende dalla lingua. Ma mostrerò le mie idee Java (e Effective Java) sull'inizializzazione delle variabili. Questi dovrebbero essere utilizzabili per molte altre lingue di livello superiore.

Costanti e variabili di classe

Le variabili di classe - contrassegnate con staticin Java - sono come costanti. Queste variabili dovrebbero normalmente essere definitive e inizializzate direttamente dopo la definizione usando =o da un blocco di inizializzatore di classe static { // initialize here }.

campi

Come in molti linguaggi di livello superiore e linguaggi di scripting verrà assegnato automaticamente un valore predefinito. Per i numeri e charquesto sarà il valore zero. Sarà per stringhe e altri oggetti null. Ora nullè pericoloso e dovrebbe essere usato con parsimonia. Quindi questi campi dovrebbero essere impostati su un valore valido il prima possibile. Il costruttore è normalmente un posto perfetto per questo. Per assicurarsi che le variabili siano impostate durante il costruttore e non vengano successivamente modificate, è possibile contrassegnarle con la finalparola chiave.

Prova a resistere all'impulso di usare nullcome una sorta di bandiera o valore speciale. È meglio includere ad esempio un campo specifico per mantenere lo stato. Un campo con il nome stateche utilizza i valori di Stateun'enumerazione sarebbe una buona scelta.

Parametri del metodo

Poiché le modifiche ai valori dei parametri (sia che si tratti di oggetti o tipi di base come numeri interi, ecc.) Non verranno visualizzate dal chiamante, i parametri devono essere contrassegnati come final. Ciò significa che i valori della variabile stessa non possono essere modificati. Si noti che il valore delle istanze di oggetti mutabili può essere modificato, il riferimento non può essere modificato per puntare a un oggetto diverso o nullcomunque.

Variabili locali

Le variabili locali non vengono inizializzate automaticamente; devono essere inizializzati prima di poter utilizzare il loro valore. Un metodo per assicurarsi che la variabile sia inizializzata consiste nell'inizializzarli direttamente a un tipo di valore predefinito. Questo è comunque qualcosa che non dovresti fare. Il più delle volte il valore predefinito non è un valore che ci si aspetterebbe.

È molto meglio definire la variabile esattamente dove serve la variabile. Se la variabile deve solo prendere un singolo valore (che è vero per la maggior parte delle variabili con un buon codice), puoi contrassegnare la variabile final. Questo si assicura che la variabile locale sia assegnata esattamente una volta, non zero o due volte. Un esempio:

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
    }
}

Nota che molte lingue ti avviseranno se una variabile rimane non inizializzata prima dell'uso. Controlla le specifiche della lingua e i forum per vedere se non ti preoccupi inutilmente.


1

Non ci sono problemi con le variabili non inizializzanti.

Il problema è solo quando leggi una variabile che non è stata ancora scritta.

A seconda del compilatore e / o del tipo di variabile, l'inizializzazione viene eseguita all'avvio dell'applicazione. O no.

È un uso comune non fare affidamento sull'inizializzazione automatica.


0

L'inizializzazione delle variabili (implicitamente o esplicitamente) è cruciale. Non inizializzare una variabile è sempre un errore (potrebbero essere inizializzati implicitamente, comunque. Vedi sotto). Complicatori moderni come il compilatore C # (come esempio) lo considerano un errore e non ti permetteranno di eseguire il codice. Una variabile non inizializzata è semplicemente inutile e dannosa. A meno che non si stia creando un generatore di numeri casuali, ci si aspetta da un pezzo di codice di produrre un risultato deterministico e riproducibile. Ciò può essere ottenuto solo se si inizia a lavorare con variabili inizializzate.

La domanda davvero interessante è se una variabile viene inizializzata automaticamente o se è necessario eseguirla manualmente. Dipende dalla lingua utilizzata. Ad esempio, in C #, i campi, ovvero "variabili" a livello di classe, vengono sempre inizializzati automaticamente sul valore predefinito per quel tipo di variabile default(T). Questo valore corrisponde a un modello di bit costituito da tutti gli zeri. Questo fa parte delle specifiche del linguaggio e non solo un dettaglio tecnico dell'implementazione del linguaggio. Pertanto puoi tranquillamente affidarti a questo. È sicuro non inizializzare esplicitamente una variabile se (e solo se) la specifica del linguaggio afferma che è inizializzata implicitamente.Se si desidera un altro valore, è necessario inizializzare esplicitamente la variabile. Però; nelle variabili locali C #, ovvero le variabili dichiarate nei metodi, non vengono inizializzate automaticamente ed è necessario inizializzare sempre la variabile in modo esplicito.


2
questa non è una domanda specifica per C #.
DougM,

@DougM: lo so. Non è una risposta specifica per C #, ho appena preso C # come esempio.
Olivier Jacot-Descombes,

Non tutte le lingue richiedono l'inizializzazione esplicita delle variabili. L'affermazione "non inizializzare è sempre un errore" è falsa e non aggiunge chiarezza alla domanda in corso. potresti voler rivedere la tua risposta.
DougM,

@DougM: hai supervisionato la mia frase "La domanda davvero interessante è se una variabile viene inizializzata automaticamente o se devi farlo manualmente."?
Olivier Jacot-Descombes,

intendi quello sepolto a metà nel mezzo di un paragrafo? sì. Avresti dovuto renderlo più evidente e aggiungere un qualificatore alla tua richiesta "sempre".
DougM,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.