2010-04-08 37 views
14

Questo era un errore che ho trovato in un'applicazione server che utilizza Valgrind.Inizializzazione di un membro di riferimento con se stesso legale?

struct Foo 
{ 
    Foo(const std::string& a) 
     : a_(a_) 
    { 
    } 
    const std::string& a_; 
}; 

con gcc -Wall non si riceve un avviso. Perché questo codice legale?

+0

Purtroppo gcc non sembra mai di mettere in guardia di auto-inizializzazione nelle liste di inizializzazione (anche con -Wall -Wextra) - è davvero fastidioso se ti piace dare ai parametri ctor lo stesso nome dei membri, perché un errore di battitura nel parametro renderà l'inizializzazione fallita in modo silenzioso. –

+0

-Wextra avverte sul parametro non utilizzato 'a', che è un buon suggerimento, ma non ha rilevato il vero problema. –

+0

Neanche con -Winit-self :( – UncleBens

risposta

2

Cosa hai viola 8.3.2/4 A ... reference shall be initialized to refer to a valid object or function. Quindi è sicuramente illegale.

Nota che non tutti i programmi errati devono essere rilevati dal compilatore, anche se onestamente avrei pensato che fosse uno di questi.

Per quel che vale, g ++ versione 4.4.1 con avvisi del compilatore massimi accesi felicemente accetta questo programma senza un avvertimento o:

int main(void) 
{ 
    int *p = 0; 
    *p = 5; 
} 
+1

I compilatori non possono generalmente rilevare tutte le violazioni, tuttavia. 'void f (int * p) {int & r = * p;/* ... * /}' l'inizializzazione del riferimento può essere legale in alcune chiamate a 'f', ma non in altre dove' p' è passato come null –

+0

È comprensibile che il compilatore non possa rilevare qualcosa che è valido o non valido in fase di esecuzione, ma in questo caso può essere statisticamente dimostrato che il riferimento non può mai essere inizializzato da un oggetto reale. – janks

+0

Sì, il mio punto era solo quello perché non puoi _always_ rileva le inizializzazioni di riferimento errate Gli implementatori del compilatore potrebbero non implementare _esanti controlli di inizializzazione di riferimento errati anche quando ci sono casi in cui è ovviamente negativo per gli occhi umani. È potenzialmente un sacco di lavoro extra (più compilazioni più lente) per un potenziale scarso guadagno. –

0

L'autoassegnazione è consentita in C/C++ (e lo considero un difetto nella lingua).

Dal punto di vista del modello di memoria, Foo :: a_ è semplicemente una posizione di memoria e nella lista di inizializzazione viene assegnato il valore di un'altra posizione di memoria, che in questo caso speciale sfortunatamente è la stessa posizione.

C'è un difetto simile in C, dove si può fare questo:

void foo() 
    { 
    int i = i; 
    } 
+0

In realtà lo standard dice esplicitamente che i riferimenti non devono occupare una locazione di memoria: '8.3.2/3 Non è specificato se un riferimento richiede o meno la memorizzazione (basic.stc)' – janks

Problemi correlati