2012-06-25 17 views
25

Eventuali duplicati:
int var = 1; void main() { int i = i; }Perché 'int i = i;' legale?

Il seguente codice può passare la compilazione sia sotto g ++ e Visual C++. Perché è legale? Sembra irragionevole e potrebbe causare bug nascosti.

int main() { 
    int i = i; 
} 
+7

Per me non è illegale, è solo un abuso di notazione. –

+8

Valuta come (i) 'int i' (ii)' i = i' nell'ordine –

+0

Penso per lo stesso motivo per cui solo "int i;" senza mai assegnare "i" è legale. – asmeurer

risposta

42

EDIT: E 'sintatticamente legale, ma i risultati in un comportamento indefinito se si utilizza x.

È non legale legale perché si assegna una variabile non inizializzata con un'altra variabile (ben diversa) non inizializzata. Solo perché compila non significa che sia legale. È una sintassi C++ valida, sì, ma non legale.

Il lato destro dell'operatore di assegnazione deve essere valutato completamente al momento dell'assegnazione. In questo caso, è i, che non è inizializzato.

Credits a Steve Jessop, che ha scavato la citazione:

4,1/1, lvalue-to-rvalue conversione

[...] se l'oggetto è inizializzato, un programma che richiede questa conversione ha un comportamento non definito.

+0

Tale argomento è circolare, avendo una variabile il cui valore non è definito non è certamente illegale. Confrontalo con semplicemente 'int i ;, che lascia anche' i' con un valore indefinito. – unwind

+0

@nhahtdh che non significa che sia legale. –

+0

Luchian, compila, e non c'è nulla nelle specifiche che non lo consenta. – OmnipotentEntity

7

Puoi lasciare g++ si avvertono di questo caso l'uso con -Winit-self (in collaborazione con -Wuninitialized), e se si trattano gli avvisi come errori, si deve soddisfare il vostro prurito.

Questa tecnica di utilizzo del costruttore di copie per l'inizializzazione automatica viene talvolta utilizzata per sopprimere il costruttore/inizializzatore predefinito di un oggetto globale dall'esecuzione. Questo può essere necessario se il costruttore predefinito dell'oggetto globale è solo per 0 inizializzare l'oggetto, ma l'oggetto è stato utilizzato prima che il costruttore sarebbe stato eseguito. Come ritorno alla C, le cifre globali sono 0 inizializzate all'avvio del programma, quindi il runtime C++ inizia a eseguire i costruttori globali. Per quei casi stretti in cui il costruttore definito che avrebbe eseguito è solo a 0 dall'oggetto, l'inizializzazione automatica non arreca alcun danno.

Nel caso generale, l'auto-inizializzazione del costruttore di copie è una cattiva pratica, poiché generalmente causerebbe lo stesso tipo di problemi che l'uso di una variabile non inizializzata causerebbe (ovvero, un comportamento non definito). Nell'esempio particolare nella domanda dell'OP,è locale a main ed è quindi non inizializzato. Il risultato della lettura di una variabile non inizializzata è sempre un comportamento indefinito.

+0

Non sembra generare alcun avviso con '-Winit-self' per me, comunque. – nhahtdh

+0

@nhahtdh: Grazie, ho aggiornato il post. Cordiali saluti – jxh

+0

_If_ l'oggetto ha un tipo definito dall'utente, e il costruttore prende l'istanza per riferimento, e mai la dereferenzia (nel costruttore), quindi il codice è legale. (Il costruttore definito dall'utente potrebbe salvare l'indirizzo, per esempio.) –

14

La ragione è consentito dalla sintassi è che ci sono alcuni casi strani dove si potrebbe plausibilmente desidera utilizzare una variabile per puntatore o riferimento nella propria inizializzazione:

struct ThingManager { 
    void *thing; 
    ThingManager(void *thing) : thing(thing) {} 
    void Speak() { 
     if (thing == (void*)this) { 
      std::cout << "I'm managing myself\n"; 
     } else { 
      std::cout << "I'm managing " << thing << "\n"; 
     } 
    } 
}; 

ThingManager self_manager(&self_manager); 
ThingManager other_manager(&self_manager); 

Quindi C++ consente di fare riferimento a un oggetto nella propria espressione di inizializzazione (il suo nome è in ambito).Quindi come sempre in C++, è il tuo problema assicurarti di non utilizzare un valore non inizializzato (il tuo esempio, int i = i; utilizza un valore non inizializzato).

Il compilatore può aiutare a identificare gli usi dei valori non inizializzati, ma lo standard non lo richiede.

2

È possibile utilizzare qualsiasi variabile precedentemente dichiarata come inizializzatore di un'altra variabile.

In questo caso, non appena il compilatore analizza int i, lo aggiunge alla tabella dei simboli, così quando vede l'inizializzatore = i, il simbolo può essere risolto dalla dichiarazione precedente.

Non è un errore perché il compilatore può dare un senso a esso in quanto può generare codice che fa esattamente ciò che specifica il codice sorgente, sette se è semanticamente sospetto. La filosofia di C e C++ è di compilare tutto ciò che può essere compilato sintatticamente. Gli errori semantici generalmente emettono solo avvisi e solo se tali avvisi sono abilitati.

Problemi correlati