À quoi sert switch
Un switch compare une valeur à une liste d'options fixes et exécute la branche qui correspond. Quand vous vous surprenez à écrire une longue chaîne de if/else if qui teste sans cesse la même variable contre différentes constantes, un switch exprime cette intention plus clairement, et compile souvent vers une table de sauts plus rapide.
Il ne fait que des tests d'égalité contre des constantes connues à la compilation sur une valeur de type entier. Il ne peut pas tester des plages, comparer des chaînes ni combiner des conditions. Pour l'un de ces cas, restez sur if/else.
Le switch de base
Vous donnez une valeur à switch, puis vous listez des étiquettes case pour les valeurs qui vous intéressent. Chaque branche se termine par break :
La valeur 3 correspond à case 3:, donc "Wednesday" s'affiche et break saute hors du switch. La branche default est le cas attrape-tout : elle s'exécute quand aucun case ne correspond. Elle est facultative, mais incluez-la sauf si vous êtes certain que toutes les valeurs sont traitées.
Notez que les étiquettes case sont de simples constantes suivies de deux-points, pas des conditions. Vous écrivez case 3:, jamais case day == 3:.
break et fall-through
C'est le piège le plus important de switch en C++. Après qu'un case correspond, l'exécution ne s'arrête pas au case suivant : elle continue tout droit jusqu'à rencontrer un break ou l'accolade fermante. Regardez ce qui se passe quand les instructions break sont absentes :
Vous pourriez vous attendre à seulement "one". Au lieu de cela, les quatre lignes s'affichent : correspondre à case 1: fait entrer dans le switch à cet endroit, puis l'exécution tombe à travers toutes les étiquettes situées en dessous. Ajoutez un break; après chaque branche et vous obtenez l'unique ligne souhaitée. Oublier un break est la source classique des bugs du type « pourquoi mon switch exécute-t-il trop de code ? ».
Fall-through intentionnel pour regrouper des cas
Le fall-through n'est pas toujours une erreur : c'est la façon idiomatique de faire partager un même corps à plusieurs cas. Laissez les cas vides (aucune instruction, aucun break) et ils s'enchaînent tous vers le bloc suivant :
'A', 'B' et 'C' aboutissent tous à la même ligne "Pass" parce que les deux premiers cas sont vides et tombent à travers vers le troisième. C'est propre et voulu. Quand vous voulez vraiment tomber à travers après avoir exécuté du code, documentez-le avec un commentaire — ou, à partir de C++17, avec l'attribut [[fallthrough]];, qui dit au compilateur « oui, c'était voulu » et fait taire les avertissements de fall-through.
switch sur des enums
switch s'associe naturellement aux enums, puisqu'un enum est exactement « une valeur parmi un ensemble fixe ». Les compilateurs peuvent aussi vous avertir si vous oubliez de traiter l'un des énumérateurs :
Avec un enum class à portée, vous devez qualifier chaque étiquette (Direction::East). Comme chaque énumérateur est couvert, aucun default n'est nécessaire — et beaucoup de compilateurs vous avertiront si vous ajoutez plus tard une cinquième direction en oubliant d'ajouter son cas. Cette aide du compilateur est une grande raison de préférer switch aux chaînes de if/else pour les enums.
Un piège : les déclarations à l'intérieur d'un case
Vous ne pouvez pas déclarer une variable avec un initialiseur dans un case et la rendre visible dans les autres cas sans lui donner sa propre portée. C'est une erreur de compilation fréquente :
switch (x) {
case 1:
int n = 10; // erreur : le saut vers case 2 contourne cette initialisation
cout << n;
break;
case 2:
cout << "two";
break;
}
Le compilateur le rejette parce que tomber dans case 2: sauterait par-dessus l'initialisation de n alors que n est encore dans la portée. La solution est d'entourer le corps du case de ses propres accolades, donnant à la variable son propre bloc :
Chaque fois qu'un case a besoin de sa propre variable locale, donnez-lui des accolades. Cela empêche aussi la variable de fuir vers les cas situés en dessous.
Suivant : la boucle for
switch et if permettent à votre programme de choisir quel code exécuter une seule fois. Mais beaucoup de travail consiste à faire la même chose de nombreuses fois : compter, parcourir une liste, répéter jusqu'à ce qu'une condition change. La boucle for est l'outil de prédilection pour cela, et c'est la page suivante.
Questions fréquentes
Quand devrais-je utiliser switch plutôt que if-else en C++ ?
Utilisez switch lorsque vous comparez une seule valeur de type entier à de nombreuses options fixes et constantes, comme un choix de menu, un numéro de jour ou un enum. Cela se lit plus clairement qu'une longue cascade de if/else if et permet au compilateur d'optimiser l'aiguillage. Restez sur if/else quand vos conditions impliquent des plages (x > 10), des valeurs à virgule flottante, des chaînes ou plusieurs variables : switch ne peut rien faire de tout cela.
Pourquoi ai-je besoin de break dans une instruction switch en C++ ?
Une fois qu'un case correspond, C++ continue d'exécuter les cas suivants jusqu'à rencontrer un break ou la fin du switch. C'est ce qu'on appelle le fall-through. break l'arrête. Oublier le break est un bug classique : vous correspondez à case 1: et exécutez accidentellement aussi le code de case 2, case 3 et du default.
Sur quels types peut-on faire un switch en C++ ?
Uniquement des types entiers ou d'énumération : int, char, short, long, bool, enum avec ou sans portée, et tout ce qui se convertit vers l'un d'eux. Vous ne pouvez pas faire de switch sur un double, un float ou un std::string : utilisez if/else pour cela. Chaque étiquette case doit être une constante connue à la compilation.