A cosa serve switch
Uno switch confronta un valore con un elenco di opzioni fisse ed esegue il ramo che corrisponde. Quando ti accorgi di scrivere una lunga catena di if/else if che continua a testare la stessa variabile con costanti diverse, uno switch esprime quell'intenzione in modo più chiaro, e spesso viene compilato in una tabella di salto più veloce.
Fa solo controlli di uguaglianza con costanti note in fase di compilazione, su un valore di tipo intero. Non può testare intervalli, confrontare stringhe o combinare condizioni. Per tutto questo, resta su if/else.
Lo switch di base
Passi a switch un valore, poi elenchi le etichette case per i valori che ti interessano. Ogni ramo termina con break:
Il valore 3 corrisponde a case 3:, quindi viene stampato "Wednesday" e break esce dallo switch. Il ramo default è quello di riserva: si esegue quando nessun case corrisponde. È facoltativo, ma includilo a meno che tu non sia certo che ogni valore sia gestito.
Nota che le etichette case sono semplici costanti seguite da due punti, non condizioni. Scrivi case 3:, mai case day == 3:.
break e fall-through
Questa è in assoluto l'insidia più importante dello switch in C++. Dopo che un case corrisponde, l'esecuzione non si ferma al case successivo: continua dritta finché non incontra un break o la graffa di chiusura. Guarda cosa succede quando mancano le istruzioni break:
Potresti aspettarti solo "one". Invece vengono stampate tutte e quattro le righe: la corrispondenza con case 1: fa entrare nello switch lì, e poi l'esecuzione scivola attraverso ogni etichetta sottostante. Aggiungi un break; dopo ogni ramo e ottieni la sola riga che volevi. Dimenticare un break è la fonte classica dei bug del tipo "perché il mio switch esegue troppo codice?".
Fall-through voluto per raggruppare i case
Il fall-through non è sempre un errore: è il modo idiomatico per far condividere a più case lo stesso corpo. Lascia i case vuoti (nessuna istruzione, nessun break) e confluiranno tutti nel blocco successivo:
'A', 'B' e 'C' finiscono tutti sulla stessa riga "Pass" perché i primi due case sono vuoti e scivolano nel terzo. È pulito e voluto. Quando vuoi davvero proseguire dopo aver eseguito del codice, documentalo con un commento, oppure da C++17 in poi con l'attributo [[fallthrough]];, che dice al compilatore "sì, lo volevo" e mette a tacere gli avvisi sul fall-through.
Switch sugli enum
switch si abbina in modo naturale agli enum, perché un enum è esattamente "uno tra un insieme fisso di valori". I compilatori possono anche avvisarti se dimentichi di gestire uno degli enumeratori:
Con un enum class con ambito devi qualificare ogni etichetta (Direction::East). Poiché ogni enumeratore è coperto, non serve un default, e molti compilatori ti avviseranno se in seguito aggiungi una quinta direzione e dimentichi il suo case. Questo aiuto del compilatore è un ottimo motivo per preferire switch alle catene di if/else con gli enum.
Un'insidia: dichiarazioni dentro un case
Non puoi dichiarare una variabile con un inizializzatore in un case e renderla visibile negli altri case senza darle un ambito. È un errore di compilazione comune:
switch (x) {
case 1:
int n = 10; // errore: il salto a case 2 salta questa inizializzazione
cout << n;
break;
case 2:
cout << "two";
break;
}
Il compilatore lo rifiuta perché entrare in case 2: salterebbe l'inizializzazione di n mentre n è ancora nel suo ambito. La soluzione è racchiudere il corpo del case tra graffe, dando alla variabile un blocco tutto suo:
Ogni volta che un case ha bisogno di una variabile locale sua, dagli le graffe. In più eviti che la variabile finisca nei case sottostanti.
Prossimo: ciclo for
switch e if permettono al programma di scegliere quale codice eseguire una volta. Ma molto lavoro consiste nel fare la stessa cosa tante volte: contare, scorrere un elenco, ripetere finché una condizione non cambia. Il ciclo for è lo strumento principale per questo, ed è la prossima pagina.
Domande frequenti
Quando usare switch invece di if-else in C++?
Usa switch quando confronti un singolo valore di tipo intero con molte opzioni fisse e costanti, come la scelta di un menu, il numero di un giorno o un enum. Si legge meglio di una lunga catena di if/else if e permette al compilatore di ottimizzare la selezione. Resta su if/else quando le condizioni riguardano intervalli (x > 10), valori in virgola mobile, stringhe o più variabili: switch non può gestire nessuno di questi casi.
Perché serve break in uno switch in C++?
Quando un case corrisponde, il C++ continua a eseguire i case successivi finché non incontra un break o la fine dello switch. Si chiama fall-through. break lo interrompe. Dimenticare il break è un bug classico: corrispondi a case 1: e per sbaglio esegui anche il codice di case 2, case 3 e del default.
Su quali tipi si può fare lo switch in C++?
Solo su tipi interi o enumerazioni: int, char, short, long, bool, enum con o senza ambito, e qualsiasi cosa si converta in uno di questi. Non puoi fare switch su un double, un float o una std::string: per quelli usa if/else. Ogni etichetta case deve essere una costante nota in fase di compilazione.