Perché dichiarare una variabile in una riga e assegnarla a quella successiva?

98

Spesso vedo nei codici C e C ++ la seguente convenzione:

some_type val;
val = something;

some_type *ptr = NULL;
ptr = &something_else;

invece di

some_type val = something;
some_type *ptr = &something_else;

Inizialmente pensavo che si trattasse di un'abitudine lasciata dai giorni in cui si dovevano dichiarare tutte le variabili locali nella parte superiore dell'ambito. Ma ho imparato a non licenziare così in fretta le abitudini degli sviluppatori veterani. Quindi, c'è una buona ragione per dichiarare in una riga e assegnarla in seguito?

    
posta Jonathan Sterling 07.05.2011 - 22:30
fonte

7 risposte

87

C

In C89 tutte le dichiarazioni dovevano essere essere all'inizio di un ambito ( { ... } ), ma questo requisito è stato eliminato rapidamente (prima con le estensioni del compilatore e successivamente con lo standard).

C ++

Questi esempi non sono gli stessi. some_type val = something; chiama il costruttore di copie mentre val = something; chiama il costruttore predefinito e quindi la funzione operator= . Questa differenza è spesso critica.

Abitudini

Alcune persone preferiscono prima dichiarare le variabili e poi definirle, nel caso in cui stanno riformattando il loro codice in un secondo momento con le dichiarazioni in un punto e la definizione in un altro.

Riguardo ai puntatori, alcune persone hanno solo l'abitudine di inizializzare ogni puntatore a NULL o nullptr , indipendentemente da cosa facciano con quel puntatore.

    
risposta data 07.05.2011 - 22:35
fonte
26

Hai taggato la tua domanda C e C ++ allo stesso tempo, mentre la risposta è significativamente diversa in queste lingue.

In primo luogo, la formulazione del titolo della tua domanda non è corretta (o, più precisamente, irrilevante per la domanda stessa). In entrambi i casi la variabile è dichiarata e definita contemporaneamente, in una riga. La differenza tra i tuoi esempi è che nella prima le variabili sono lasciate non inizializzate o inizializzate con un valore fittizio e quindi è assegnate a valore significativo dopo. Nel secondo esempio le variabili sono inizializzate subito.

In secondo luogo, in linguaggio C ++, come @nightcracker ha notato nella sua risposta questi due costrutti sono semanticamente differenti. Il primo si basa sull'inizializzazione mentre il secondo su incarico. In C ++ queste operazioni sono sovraccariche e quindi possono potenzialmente portare a risultati diversi (anche se si può notare che produrre sovraccarichi non equivalenti di inizializzazione e assegnazione non è una buona idea).

Nel linguaggio C standard originale (C89 / 90) è illegale dichiarare variabili nel mezzo del blocco, motivo per cui si potrebbero vedere le variabili dichiarate non inizializzate (o inizializzate con valori dummy) all'inizio del blocco e poi ha assegnato valori significativi successivamente, quando questi valori significativi diventano disponibili.

Nel linguaggio C99 è OK dichiarare le variabili nel mezzo del blocco (proprio come in C ++), il che significa che il primo approccio è necessario solo in alcune situazioni specifiche quando l'inizializzatore non è noto nel punto di dichiarazione. (Questo vale anche per il C ++).

    
risposta data 07.05.2011 - 22:47
fonte
13

Penso che sia una vecchia abitudine, abbandonata dai tempi della "dichiarazione locale". E quindi come risposta alla tua domanda: No, non penso ci sia una buona ragione. Non lo faccio mai da solo.

    
risposta data 07.05.2011 - 22:35
fonte
4

Ho detto qualcosa a riguardo in la mia risposta a una domanda di Helium3 .

Fondamentalmente, dico che è un aiuto visivo per vedere facilmente cosa è cambiato.

if (a == 0) {
    struct whatever *myobject = 0;
    /* did 'myobject' (the pointer) get assigned?
    ** or was it '*myobject' (the struct)? */
}

e

if (a == 0) {
    struct whatever *myobject;
    myobject = 0;
    /* 'myobject' (the pointer) got assigned */
}
    
risposta data 07.05.2011 - 22:42
fonte
4

Le altre risposte sono piuttosto buone. C'è una certa storia attorno a questo in C. In C ++ c'è la differenza tra un costruttore e un operatore di assegnazione.

Sono sorpreso che nessuno menzioni il punto in più: mantenere le dichiarazioni separate dall'uso di una variabile a volte può essere molto più leggibile.

Visivamente parlando, durante la lettura del codice, gli artefatti più banali, come i tipi e i nomi delle variabili, non sono ciò che ti salta addosso. Sono le dichiarazioni che di solito ti interessano di più, passano più tempo a fissare, e quindi c'è una tendenza a dare un'occhiata a tutto il resto.

Se ho alcuni tipi, nomi e compiti che si svolgono tutti nello stesso spazio ristretto, è un po 'di sovraccarico di informazioni. Inoltre, significa che qualcosa di importante sta accadendo nello spazio di cui mi guardo di solito.

Può sembrare un po 'contro-intuitivo dire, ma questa è un'istanza in cui rendere la tua fonte occupare più spazio verticale può renderla migliore. Lo vedo come il motivo per cui non dovresti scrivere linee affollate che fanno pazze quantità di aritmetica puntatore e assegnazione in uno stretto spazio verticale - solo perché la lingua ti lascia andare via con queste cose non significa che dovresti fare tutto il tempo. : -)

    
risposta data 08.05.2011 - 00:01
fonte
2

In C, questa era la pratica standard perché le variabili dovevano essere dichiarate all'inizio della funzione, diversamente dal C ++, dove poteva essere dichiarato ovunque nel corpo della funzione da utilizzare successivamente. I puntatori sono stati impostati su 0 o NULL, perché si sono limitati a fare in modo che il puntatore non indicasse nulla. Altrimenti, non c'è alcun vantaggio significativo a cui possa pensare, cosa che costringe chiunque a fare così.

    
risposta data 07.05.2011 - 22:39
fonte
2

Professionisti per la localizzazione delle definizioni di variabili e la loro inizializzazione significativa:

  • se alle variabili viene normalmente assegnato un valore significativo quando appaiono per la prima volta nel codice (un'altra prospettiva sulla stessa cosa: si ritarda il loro aspetto fino a quando un valore significativo è disponibile) quindi nessuna possibilità di viene accidentalmente usato con un valore priva di significato o non inizializzato (che può facilmente accadere se un'inizializzazione viene accidentalmente ignorata a causa di dichiarazioni condizionali, valutazione di cortocircuiti, eccezioni ecc.)

  • può essere più efficiente

    • evita i costi generali dell'impostazione del valore iniziale (costruzione o inizializzazione predefinite per alcuni valori sentinella come NULL)
    • operator= a volte può essere meno efficiente e richiede un oggetto temporaneo
    • a volte (specialmente per le funzioni inline) l'ottimizzatore può rimuovere alcune / tutte le inefficienze

  • riducendo al minimo l'ambito delle variabili a sua volta riduce al minimo media numero di variabili contemporaneamente nell'ambito : questo

    • rende più facile per monitorare mentalmente le variabili in ambito, i flussi di esecuzione e le istruzioni che potrebbero influire su tali variabili e l'importazione del loro valore
    • almeno per alcuni oggetti complessi e opachi, questo riduce l'utilizzo delle risorse (heap, thread, memoria condivisa, descrittori) del programma
  • a volte più conciso in quanto non stai ripetendo il nome della variabile in una definizione, quindi in un compito significativo iniziale

  • necessario per alcuni tipi come i riferimenti e quando vuoi che l'oggetto sia const

Argomenti per il raggruppamento delle definizioni di variabili:

  • a volte è conveniente e / o conciso a calcolare il tipo di un numero di variabili:

    the_same_type v1, v2, v3;

    (se il motivo è solo che il nome del tipo è troppo lungo o complesso, a typedef a volte può essere migliore)

  • a volte è preferibile raggruppare le variabili indipendentemente dal loro utilizzo per enfatizzare l'insieme di variabili (e tipi) coinvolti in alcune operazioni:

    type v1;
    type v2; type v3;

    Questo enfatizza la comunanza di tipo e rende un po 'più facile cambiarli, mentre si attacca ancora a una variabile per riga che facilita il copia-incolla, // commentando ecc.

Come spesso accade nella programmazione, mentre nella maggior parte delle situazioni può esserci un chiaro beneficio empirico per una pratica, l'altra pratica può essere davvero molto più efficace in alcuni casi.

    
risposta data 09.05.2011 - 11:57
fonte

Leggi altre domande sui tag