2010-03-06 13 views
69

Considerate seguente codice:Quali sono i segni dell'inizializzazione delle croci?

#include <iostream> 
using namespace std; 

int main() 
{ 
    int x, y, i; 
    cin >> x >> y >> i; 
    switch(i) { 
     case 1: 
      // int r = x + y; -- OK 
      int r = 1; // Failed to Compile 
      cout << r; 
      break; 
     case 2: 
      r = x - y; 
      cout << r; 
      break; 
    }; 
} 

G ++ lamenta crosses initialization of 'int r' domande .Le mie sono:

  1. Che cosa è crosses initialization?
  2. Perché il primo inizializzatore x + y ha superato la compilazione, ma successivamente non è riuscito?
  3. Quali sono i problemi del cosiddetto crosses initialization?

EDIT:
So che dovrei usare le parentesi per specificare l'ambito di r ma voglio sapere perché, ad esempio perché non POD non poteva essere definito in multi-caso switch.

Grazie.

+1

La mia comprensione, date le risposte di seguito, per il punto 3 è che questo errore è una restrizione eccessiva di C++. Se r non viene usato dopo l'etichetta, non c'è alcun impatto (anche se l'esempio qui usa r, può essere rimosso nel caso 2 e il compilatore darebbe lo stesso errore). La prova migliore è che è permesso in C, e persino in C11. – calandoa

+0

Possibile duplicato di [Errore: vai all'etichetta del caso] (http://stackoverflow.com/questions/5685471/error-jump-to-case-label) –

risposta

81

La versione con int r = x + y; non verrà compilato neanche.

Il problema è che è possibile che r entri nello scope senza che venga eseguito l'inizializzatore. Il codice verrebbe compilato correttamente se si rimuoveva completamente l'inizializzatore (ad esempio, la riga avrebbe letto int r;).

La cosa migliore che si può fare è limitare l'ambito della variabile. In questo modo soddisferete sia il compilatore che il lettore.

switch(i) 
{ 
case 1: 
    { 
     int r = 1; 
     cout << r; 
    } 
    break; 
case 2: 
    { 
     int r = x - y; 
     cout << r; 
    } 
    break; 
}; 

The Standard dice (6,7/3):

It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps from a point where a local variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has POD type (3.9) and is declared without an initializer (8.5).

+0

Ma il mio G ++ non consente 'int r = x + y'. – Jichao

+9

Beh, il mio g ++ no. Controlla di nuovo o aggiorna il compilatore. – avakar

+0

grazie, mi è stato d'aiuto. Penso che il compilatore C non permetta nemmeno alla dichiarazione di venire _after_ qualche codice. Apparentemente C99 lo consente però ... http://stackoverflow.com/questions/7859424/why-was-mixing-declarations-and-code-forbidden-up-until-c99 –

31

Si dovrebbe mettere il contenuto del case tra parentesi per dargli la portata, in questo modo è possibile dichiarare le variabili locali all'interno di esso:

switch(i) { 
    case 1: 
     { 
      // int r = x + y; -- OK 
      int r = 1; // Failed to Compile 
      cout << r; 
     } 
     break; 
    case 2: 
     ... 
     break; 
}; 
2

È possibile trasferire in un blocco, ma non in modo che aggira le dichiarazioni con l'inizializzazione. Un programma che salta da un punto in cui una variabile locale con durata dell'archiviazione automatica non è nell'ambito di un punto in cui è nell'ambito dell'ambito è mal formata a meno che la variabile non abbia il tipo POD e sia dichiarata senza un inizializzatore.

[Example: Code: 

void f() 
{ 
    // ... 
    goto lx; // ill-formed: jump into scope of `a' 
    // ... 
ly: 
    X a = 1; 
    // ... 
lx: 
    goto ly; // ok, jump implies destructor 
// call for `a' followed by construction 
// again immediately following label ly 
} 

--end example] 

Il trasferimento dalla condizione di un'istruzione di commutazione a un'etichetta di caso è considerato un salto in questo senso.

+1

Benvenuti in Stack Overflow. Dovresti fornire fonti per le tue citazioni, questo è C++ 03: 6.7/3. Capita anche di essere lo stesso paragrafo che ho citato nella mia risposta. – avakar

0

Suggerisco di promuovere la variabile r prima dell'istruzione switch. Se si desidera utilizzare una variabile attraverso i case blocchi, (o lo stesso nome di variabile, ma diversi usi), definirlo prima che l'istruzione switch:

#include <iostream> 
using namespace std; 

int main() 
{ 
    int x, y, i; 
    cin >> x >> y >> i; 
// Define the variable before the switch. 
    int r; 
    switch(i) { 
     case 1: 
      r = x + y 
      cout << r; 
      break; 
     case 2: 
      r = x - y; 
      cout << r; 
      break; 
    }; 
} 

Uno dei vantaggi è che il compilatore non deve eseguire allocazione locale (alias spinta nello stack) in ogni blocco case.

Uno svantaggio di questo approccio è quando i casi "cadono" in altri casi (ad es.senza utilizzare break), poiché la variabile avrà un valore precedente.

+2

Suggerirei di farlo al contrario. Il compilatore non deve eseguire "allocazione locale" in entrambi i casi (e in pratica non lo farà). – avakar

Problemi correlati