Sollten switch-Anweisungen immer eine Standardklausel enthalten?

255

In einer meiner ersten Codeüberprüfungen (vor einiger Zeit) wurde mir gesagt, dass es empfehlenswert ist, eine Standardklausel in alle switch-Anweisungen aufzunehmen. Ich habe mich kürzlich an diesen Rat erinnert, kann mich aber nicht erinnern, was die Rechtfertigung war. Es klingt jetzt ziemlich seltsam für mich.

  1. Gibt es einen vernünftigen Grund, immer eine Standardanweisung einzuschließen?

  2. Ist diese Sprache abhängig? Ich kann mich nicht erinnern, welche Sprache ich damals verwendet habe - vielleicht gilt dies für einige Sprachen und nicht für andere?

tttppp
quelle
9
Es wird zu einem großen Teil
sprachabhängig sein

Antworten:

277

Switch Cases sollten fast immer einen defaultCase haben.

Gründe für die Verwendung von a default

1.Um einen unerwarteten Wert zu "fangen"

switch(type)
{
    case 1:
        //something
    case 2:
        //something else
    default:
        // unknown type! based on the language,
        // there should probably be some error-handling
        // here, maybe an exception
}

2. Um 'Standard'-Aktionen zu behandeln, bei denen es sich um besondere Verhaltensweisen handelt.

Sie sehen dies VIEL in menügesteuerten Programmen und Bash-Shell-Skripten. Dies wird möglicherweise auch angezeigt, wenn eine Variable außerhalb des Switch-Falls deklariert, aber nicht initialisiert wird und in jedem Fall auf etwas anderes initialisiert wird. Hier muss die Standardeinstellung ebenfalls initialisiert werden, damit der Zeilencode, der auf die Variable zugreift, keinen Fehler auslöst.

3. Um jemandem, der Ihren Code liest, zu zeigen, dass Sie diesen Fall behandelt haben.

variable = (variable == "value") ? 1 : 2;
switch(variable)
{
    case 1:
        // something
    case 2:
        // something else
    default:
        // will NOT execute because of the line preceding the switch.
}

Dies war ein stark vereinfachtes Beispiel, aber der Punkt ist, dass sich jemand, der den Code liest, nicht fragen sollte, warum er variablenicht etwas anderes als 1 oder 2 sein kann.


Der einzige Fall, den ich mir vorstellen kann , NICHT zu verwenden, defaultist, wenn der Schalter etwas überprüft, bei dem es ziemlich offensichtlich ist, dass jede andere Alternative glücklich ignoriert werden kann

switch(keystroke)
{
    case 'w':
        // move up
    case 'a':
        // move left
    case 's':
        // move down
    case 'd':
        // move right
    // no default really required here
}
Vanwaril
quelle
25
Ihr Beispiel für Tastenanschläge widerspricht dem Rest von dem, was Sie gerade gesagt haben. : | Ich denke, ein bisschen mehr Erklärung wäre sinnvoll, wie zum Beispiel: Sie interessieren sich in diesem Fall nicht für eine Standardeinstellung, denn wenn eine andere Taste gedrückt wird, ist es Ihnen egal, aber wenn eine Variable übergeben wird, die anders ist als erwartet, ist uns das wichtig .
Andrew
1
Wenn Sie einen GET-Parameter überprüfen, möchten Sie möglicherweise nicht, dass jedes Mal eine Ausnahme ausgelöst wird, wenn ein Benutzer die get-URL in etwas ändert, das nicht gültig ist: [
Andrew,
4
@ Andrew WASD ist für Bewegungen von Computerspielcharakteren üblich. Sie benötigen keine Standardaktion, da andere Tasten anderen Interaktionen zugewiesen werden könnten. Bei dieser Art von Schalter ist es gut, Bewegungsfunktionen aufzurufen.
jemiloii
13
Einige Compiler warnen beim Einschalten einer Aufzählung, wenn ein Fall übersehen wird, und das Hinzufügen eines Standardfalls unterdrückt diese Warnung. Da dies meiner Erfahrung nach eine sehr häufige Fehlerquelle ist (das Vergessen, einen Schalter irgendwo nach dem Hinzufügen eines Enum-Werts zu aktualisieren), scheint dies ein sehr guter Grund zu sein, einen Standardfall wegzulassen.
Rdb
3
@virusrocks Wenn Ihr Zustand eine Aufzählung ist, können Sie immer noch unerwartete Werte haben. Wenn Sie beispielsweise der Aufzählung einen neuen Wert hinzufügen und vergessen, einen Schalter zu aktualisieren. In einigen Sprachen können Sie auch Ganzzahlen ganzzahlige Werte zuweisen. In C ++ enum MyEnum { FOO = 0, BAR = 1 }; MyEnum value = (MyEnum)2;wird eine gültige MyEnumInstanz erstellt, die nicht gleich FOOoder ist BAR. Wenn eines dieser Probleme einen Fehler in Ihrem Projekt verursachen würde, hilft Ihnen ein Standardfall dabei, den Fehler sehr schnell zu finden, häufig ohne dass ein Debugger erforderlich ist!
CDgraham
54

Nein.

Was ist, wenn es keine Standardaktion gibt? Der Kontext ist wichtig. Was ist, wenn Sie nur auf wenige Werte reagieren möchten?

Nehmen Sie das Beispiel des Lesens von Tastendrücken für ein Spiel

switch(a)
{
   case 'w':
     // Move Up
     break;
   case 's':
     // Move Down
     break;
   case 'a':
     // Move Left
     break;
   case 'd':
     // Move Right
     break;
}

Hinzufügen:

default: // Do nothing

Ist nur Zeitverschwendung und erhöht die Komplexität des Codes ohne Grund.

Jared Kells
quelle
14
Gutes Beispiel. Tatsächlich macht das Hinzufügen einer Standardklausel mit einem einfachen // do nothingKommentar jedoch deutlich, dass es "in Ordnung" ist, wenn nicht alle Fälle abgedeckt sind, im Gegensatz zu anderen switch-Anweisungen, bei denen dies "nicht in Ordnung" wäre.
Der Nagel
8
Bei der Codierung geht es nicht nur um die Behandlung einiger Fälle. Es dient auch als Dokument. Wenn Sie default: und Kommentare wie // Do nichts oder etwas anderes schreiben, wird die Lesbarkeit des Codes besser.
JongAm Park
22
Stimme den anderen Kommentaren nicht zu. Standard hinzufügen // Nichts tun fügt nur sehr wenig hinzu, wenn Sie nicht wissen, wie Code funktioniert. Ich kann eine switch-Anweisung ohne Standard anzeigen und weiß, dass der Standard darin besteht, nichts zu tun. Das Hinzufügen von Unordnung macht dies nicht offensichtlicher.
Robert Noack
Genau. Es ist im gleichen Konzept der Übergabe aller Post-Parameter. Sie kümmern sich um diejenigen, die Ihnen wichtig sind, nicht um die anderen.
Jimmy Kane
2
@jybrd Wenn Sie nicht darauf vertrauen, dass der vorherige Entwickler die Standardeinstellung absichtlich weggelassen hat, warum sollten Sie dann darauf vertrauen, dass sie korrekt waren, um sie einzufügen? Eine Standardeinstellung kann versehentlich genauso einfach leer sein wie vollständig fehlen. Ein Kommentar ist für etwas so Triviales nicht notwendig. Das ist Code-Unordnung. Schreiben Sie Unit-Tests mit vollständiger Abdeckung, um stattdessen Ihre Absichten zu zeigen. (Nur meine Meinung)
Robert Noack
45

In einigen Situationen kann es tatsächlich von Vorteil sein, NICHT den Standardfall zu haben.

Wenn es sich bei Ihren Switch-Fällen um Aufzählungswerte handelt und Sie keinen Standardfall haben, können Sie eine Compiler-Warnung erhalten, wenn Sie Fälle vermissen. Auf diese Weise können Sie sich beim Kompilieren über das Problem informieren, wenn in Zukunft neue Aufzählungswerte hinzugefügt werden und Sie vergessen, Fälle für diese Werte im Switch hinzuzufügen. Sie sollten weiterhin sicherstellen, dass der Code geeignete Maßnahmen für nicht behandelte Werte ergreift, falls ein ungültiger Wert in den Aufzählungstyp umgewandelt wurde. Dies funktioniert also am besten in einfachen Fällen, in denen Sie innerhalb des Enum-Falls zurückkehren können, anstatt zu brechen.

enum SomeEnum
{
    ENUM_1,
    ENUM_2,
    // More ENUM values may be added in future
};

int foo(SomeEnum value)
{
    switch (value)
    {
    case ENUM_1:
        return 1;
    case ENUM_2:
        return 2;
    }
    // handle invalid values here
    return 0;
 }
Harlan Kassler
quelle
Dies ist eine wichtige Beobachtung! In Java gilt dies noch mehr, da Sie damit keine Ints in Enums umwandeln können.
Lii
2
In Ihrem Beispiel könnten Sie eine Ausnahme auslösen, anstatt nach der switch-Anweisung zurückzukehren. Auf diese Weise können Sie sowohl statische Überprüfungen durch den Compiler durchführen als auch einen eindeutigen Fehler erhalten, wenn etwas Unerwartetes passiert.
Lii
1
Genau. In Swift muss der Schalter beispielsweise vollständig sein, sonst wird ein Compilerfehler angezeigt! Wenn Sie eine Standardeinstellung angeben, wird dieser nützliche Fehler nur stummgeschaltet. Wenn Sie jedoch einen Standard angeben, wenn alle Fälle behandelt werden, wird tatsächlich eine Compiler-Warnung ausgegeben (nicht erreichbare Anweisung).
Andy
1
Es wurde nur ein Fehler behoben, der eine Warnung des Compilers ausgelöst hätte, wenn es keinen Standard gegeben hätte. Daher sollte eine Umschaltvariable für Umschaltvariablen im Allgemeinen keinen Standard haben.
Notan
42

Ich würde immer eine Standardklausel verwenden, egal in welcher Sprache Sie arbeiten.

Dinge können und können schief gehen. Werte werden nicht das sein, was Sie erwarten, und so weiter.

Wenn Sie keine Standardklausel einfügen möchten, können Sie sicher sein, dass Sie die möglichen Werte kennen. Wenn Sie glauben, die Menge der möglichen Werte zu kennen, möchten Sie darüber informiert werden, wenn der Wert außerhalb dieser Menge möglicher Werte liegt - es ist sicherlich ein Fehler.

Aus diesem Grund sollten Sie immer eine Standardklausel verwenden und einen Fehler auslösen, beispielsweise in Java:

switch (myVar) {
   case 1: ......; break;
   case 2: ......; break;
   default: throw new RuntimeException("unreachable");
}

Es gibt keinen Grund, mehr Informationen als nur die "nicht erreichbare" Zeichenfolge anzugeben. Wenn dies tatsächlich passiert, müssen Sie sich ohnehin die Quelle und die Werte der Variablen usw. ansehen, und die Ausnahmestapelverfolgung enthält diese Zeilennummer, sodass Sie keine Zeit damit verschwenden müssen, mehr Text in die Ausnahmemeldung zu schreiben.

Adrian Smith
quelle
39
Ich würde es vorziehen, throw new RuntimeException("myVar invalid " + myVar);da dies Ihnen möglicherweise genügend Informationen liefert, um den Fehler herauszufinden und zu beheben, ohne einen Debugger verwenden und Variablen untersuchen zu müssen. Dies kann schwierig sein, wenn dies ein selten auftretendes Problem ist, das schwer zu reproduzieren ist.
Chris Dodd
1
Was ist, wenn es keine Fehlerbedingung ist, dass der Wert nicht mit einem der Fälle übereinstimmt?
Gabe
4
Wenn es sich nicht um eine Fehlerbedingung handelt, ist eine nicht erforderlich default:. Aber meistens lässt man einen Standard weg, weil man denkt, dass er myVarniemals einen anderen Wert als den aufgelisteten haben kann; Ich kann jedoch nicht zählen, wie oft ich im wirklichen Leben überrascht war, als die Variable einen anderen Wert hatte als die Werte, die sie "möglicherweise" haben könnte. In diesen Fällen war ich dankbar für die Ausnahme, die mich sofort erkennen ließ, anstatt später einen anderen Fehler (schwieriger zu debuggen) oder eine falsche Antwort (wird beim Testen möglicherweise übersehen) zu verursachen.
Adrian Smith
2
Ich stimme Adrian zu. Scheitern Sie hart und scheitern Sie früh.
Slappy
Ich ziehe es vor, ein AssertionErrorstatt zu werfen RuntimeException, da diese Situation einer Behauptung sehr ähnlich ist, die besagt, dass dies myVareiner der behandelten Werte ist. Auch die Wahrscheinlichkeit, dass jemand den Fehler fängt und verschluckt, ist geringer.
Philipp Wendler
15

In meinem Unternehmen schreiben wir Software für den Avionik- und Verteidigungsmarkt und fügen immer eine Standardanweisung hinzu, da ALLE Fälle in einer switch-Anweisung explizit behandelt werden müssen (auch wenn es sich nur um einen Kommentar mit der Aufschrift "Nichts tun" handelt). Wir können es uns nicht leisten, dass sich die Software nur schlecht verhält oder bei unerwarteten (oder sogar für unmöglich gehaltenen) Werten abstürzt.

Es kann diskutiert werden, dass ein Standardfall nicht immer notwendig ist, aber indem er immer benötigt wird, kann er von unseren Codeanalysatoren leicht überprüft werden.

Kurt Pattyn
quelle
1
Ich habe die gleichen Anforderungen, wo ich arbeite; Wir schreiben Code für eingebettete µController, die strenge Sicherheitsprüfungen bestehen müssen und häufig EMI ausgesetzt sind. Es wäre unverantwortlich anzunehmen, dass eine aufgezählte Variable niemals einen Wert hat, der nicht in der Aufzählungsliste enthalten ist.
Oosterwal
12

Sollte eine "switch" -Anweisung immer eine Standardklausel enthalten? Nein, sollte es normalerweise eine Standardeinstellung enthalten.

Das Einfügen einer Standardklausel ist nur dann sinnvoll, wenn etwas zu tun ist, z. B. eine Fehlerbedingung geltend zu machen oder ein Standardverhalten bereitzustellen. Das Einschließen eines "nur weil" ist eine Frachtkult-Programmierung und bietet keinen Wert. Es ist das "switch" -Äquivalent zu der Aussage, dass alle "if" -Anweisungen ein "else" enthalten sollten.

Hier ist ein triviales Beispiel dafür, wo es keinen Sinn macht:

void PrintSign(int i)
{
    switch (Math.Sign(i))
    {
    case 1:
        Console.Write("positive ");
        break;
    case -1:
        Console.Write("negative ");
        break;
    default: // useless
    }
    Console.Write("integer");
}

Dies entspricht:

void PrintSign(int i)
{
    int sgn = Math.Sign(i);
    if (sgn == 1)
        Console.Write("positive ");
    else if (sgn == -1)
        Console.Write("negative ");
    else // also useless
    {
    }
    Console.Write("integer");
}
Gabe
quelle
Ich bin nicht einverstanden. IMHO, das einzige Mal, wenn ein Standard nicht existieren sollte, ist, wenn es für jetzt und für immer keine Möglichkeit gibt, dass sich der Satz von Eingaben ändern kann und Sie jeden möglichen Wert abgedeckt haben. Der einfachste Fall, den ich mir vorstellen kann, ist ein boolescher Wert aus einer Datenbank, bei dem die einzigen Antworten (bis sich SQL ändert!) Wahr, falsch und NULL sind. In jedem anderen Fall ein Standardwert mit der Behauptung oder Ausnahme "Sollte nicht passieren!" macht Sinn. Wenn sich Ihr Code ändert und Sie einen oder mehrere neue Werte haben, können Sie sicherstellen, dass Sie für sie codieren, und Ihre Tests werden explodieren, wenn Sie dies nicht tun.
Harper Shelby
4
@Harper: Ihr Beispiel fällt unter die Kategorie "Fehlerbedingung geltend machen".
Gabe
Ich würde behaupten, dass mein Beispiel die Norm ist und dass die geringe Anzahl von Fällen, in denen man zu 100% sicher sein kann, dass jeder mögliche Fall abgedeckt ist und ein Standard nicht benötigt wird, die Ausnahme ist. Ihre Antwort ist so formuliert, dass sie (zumindest für mich) so klingt, als ob die Standardeinstellung "Nichtstun" häufig vorkommt.
Harper Shelby
@Harper: OK, ich habe den Wortlaut geändert, um anzuzeigen, dass die Nichtstun-Situation weniger häufig ist.
Gabe
4
Ich denke, ein default:in diesen Fällen kodifiziert Ihre Annahmen. Ist es beispielsweise in Ordnung, wann sgn==0gedruckt werden soll integer(weder positiv noch negativ), oder ist das ein Fehler? Für mich ist es schwer zu sagen, diesen Code zu lesen. Ich würde annehmen, dass Sie zeroin diesem Fall nicht schreiben möchten integerund dass der Programmierer die Annahme getroffen hat, dass sgnnur -1 oder +1 sein kann. Wenn dies der Fall default:wäre, könnte der Programmierer den Annahmefehler frühzeitig erkennen und den Code ändern.
Adrian Smith
7

Soweit ich es sehe, ist die Antwort "Standard" optional. Die Aussage, dass ein Schalter immer eine Standardeinstellung enthalten muss, ist wie die Aussage, dass jedes "if-elseif" ein "else" enthalten muss. Wenn standardmäßig eine Logik ausgeführt werden muss, sollte die Anweisung 'default' vorhanden sein. Andernfalls kann der Code weiterhin ausgeführt werden, ohne dass etwas unternommen wird.

Gershon Herczeg
quelle
6

Eine Standardklausel zu haben, wenn sie nicht wirklich benötigt wird, ist defensive Programmierung. Dies führt normalerweise zu Code, der aufgrund von zu viel Fehlerbehandlungscode zu komplex ist. Dieser Fehlerbehandlungs- und Erkennungscode beeinträchtigt die Lesbarkeit des Codes, erschwert die Wartung und führt schließlich zu mehr Fehlern als behoben.

Ich glaube also, wenn der Standard nicht erreicht werden sollte, müssen Sie ihn nicht hinzufügen.

Beachten Sie, dass "sollte nicht erreicht werden" bedeutet, dass es ein Fehler in der Software ist, wenn es erreicht wird. Sie müssen Werte testen, die aufgrund von Benutzereingaben usw. unerwünschte Werte enthalten können.

Ophir Yoktan
quelle
3
Ein weiterer häufiger Grund für unerwartete Fälle: Andere Teile des Codes werden möglicherweise Jahre später geändert.
Hendrik Brummermann
In der Tat ist dies ein sehr gefährliches Verhalten. Zumindest würde ich eine assert () -Klausel hinzufügen. Dann ist es leicht zu erkennen, wenn ein Fehler vorliegt.
Kurt Pattyn
5

Ich würde sagen, es hängt von der Sprache ab, aber in C ist es wahrscheinlich besser, wenn Sie einen Aufzählungstyp einschalten und jeden möglichen Wert verarbeiten, KEINEN Standardfall einzuschließen. Auf diese Weise gibt Ihnen ein kompetenter Compiler eine Warnung über den fehlenden Fall, wenn Sie später ein zusätzliches Enum-Tag hinzufügen und vergessen, es dem Switch hinzuzufügen.

Chris Dodd
quelle
5
"Jeder mögliche Wert" wird wahrscheinlich nicht mit Aufzählungen behandelt. Sie können eine Ganzzahl in eine Aufzählung umwandeln, auch wenn dieser bestimmte Wert nicht explizit definiert ist. Und welcher Compiler warnt vor dem fehlenden Fall?
TrueWill
1
@TrueWill: Ja, Sie können explizite Casts verwenden, um verschleierten Code zu schreiben, der nicht zu verstehen ist. Um verständlichen Code zu schreiben, sollten Sie dies vermeiden. gcc -Wall(Art des kleinsten gemeinsamen Nenners kompetenter Compiler) gibt Warnungen vor Aufzählungen aus, die in switch-Anweisungen nicht behandelt werden.
Chris Dodd
4

Wenn Sie wissen, dass die switch-Anweisung immer nur einen streng definierten Satz von Beschriftungen oder Werten enthält, tun Sie dies einfach, um die Basen abzudecken. Auf diese Weise erhalten Sie immer ein gültiges Ergebnis. Setzen Sie einfach die Standardeinstellung über die Beschriftung, die programmgesteuert / logisch wäre Seien Sie der beste Handler für andere Werte.

switch(ResponseValue)
{
    default:
    case No:
        return false;
    case Yes;
        return true;
}
deegee
quelle
Wird der Doppelpunkt danach hier defaultnoch benötigt? Oder erlaubt dies eine spezielle Syntax, mit der Sie sie weglassen konnten?
Ponkadoodle
Der Doppelpunkt ist erforderlich, das war ein Tippfehler. Vielen Dank, dass Sie mich darauf aufmerksam gemacht haben.
Deegee
3

Zumindest ist es in Java nicht obligatorisch. Laut JLS kann höchstens ein Standardfall vorliegen. Dies bedeutet, dass kein Standardfall akzeptabel ist. Es hängt manchmal auch vom Kontext ab, in dem Sie die switch-Anweisung verwenden. In Java beispielsweise erfordert der folgende Switch-Block keinen Standardfall

private static void switch1(String name) {
    switch (name) {
    case "Monday":
        System.out.println("Monday");
        break;
    case "Tuesday":
        System.out.println("Tuesday");
        break;
    }
}

Bei der folgenden Methode, bei der erwartet wird, dass ein String zurückgegeben wird, ist der Standardfall hilfreich, um Kompilierungsfehler zu vermeiden

    private static String switch2(String name) {
    switch (name) {
    case "Monday":
        System.out.println("Monday");
        return name;

    case "Tuesday":
        System.out.println("Tuesday");
        return name;

    default:
        return name;
    }
}

Sie können zwar Kompilierungsfehler für die oben beschriebene Methode vermeiden, ohne einen Standardfall zu haben, indem Sie am Ende nur eine return-Anweisung haben. Wenn Sie jedoch einen Standardfall angeben, wird diese besser lesbar.

Shiva Kumar
quelle
3

Einige (veraltete) Richtlinien sagen dies, wie beispielsweise MISRA C :

Voraussetzung für eine endgültige Standardklausel ist die defensive Programmierung. Diese Klausel muss entweder geeignete Maßnahmen ergreifen oder einen geeigneten Kommentar dazu enthalten, warum keine Maßnahmen ergriffen werden.

Dieser Rat ist veraltet, da er nicht auf derzeit relevanten Kriterien basiert. Die krasse Auslassung war das, was Harlan Kassler sagte:

Wenn Sie den Standardfall weglassen, kann der Compiler optional warnen oder fehlschlagen, wenn ein nicht behandelter Fall angezeigt wird. Die statische Überprüfbarkeit ist schließlich besser als jede dynamische Prüfung und daher kein würdiges Opfer, wenn Sie auch die dynamische Prüfung benötigen.

Wie Harlan ebenfalls demonstrierte, kann das funktionale Äquivalent eines Standardfalls nach dem Wechsel neu erstellt werden. Was trivial ist, wenn jeder Fall eine vorzeitige Rückkehr ist.

Die typische Notwendigkeit einer dynamischen Prüfung ist im weitesten Sinne die Eingabebehandlung. Wenn ein Wert außerhalb der Kontrolle des Programms liegt, kann er nicht als vertrauenswürdig eingestuft werden.

Hier vertritt Misra auch den Standpunkt einer extrem defensiven Programmierung. Solange ein ungültiger Wert physisch darstellbar ist, muss er überprüft werden, unabhängig davon, ob das Programm nachweislich korrekt ist. Dies ist sinnvoll, wenn die Software bei Hardwarefehlern so zuverlässig wie möglich sein muss. Aber wie Ophir Yoktan sagte, ist es für die meisten Software besser, Fehler nicht zu "behandeln". Die letztere Praxis wird manchmal als anstößige Programmierung bezeichnet .

user2394284
quelle
2

Sie sollten eine Standardeinstellung haben, um unerwartete Werte abzufangen.

Ich bin jedoch nicht mit Adrian Smith einverstanden, dass Ihre Standardfehlermeldung etwas völlig Bedeutungsloses sein sollte. Möglicherweise gibt es einen nicht behandelten Fall, den Sie nicht vorhergesehen haben (was der Punkt ist), den Ihr Benutzer am Ende sehen wird, und eine Nachricht wie "nicht erreichbar" ist völlig sinnlos und hilft niemandem in dieser Situation.

Wie oft hatten Sie ein völlig bedeutungsloses BSOD? Oder eine schwerwiegende Ausnahme @ 0x352FBB3C32342?

John Hunt
quelle
Beispiel: Denken Sie daran, dass nicht nur der Entwickler immer Fehlermeldungen sieht. Wir leben in der realen Welt, Menschen machen Fehler.
John Hunt
2

Wenn der Schaltwert ( Schalter (Variable )) den Standardfall nicht erreichen kann, wird der Standardfall überhaupt nicht benötigt. Selbst wenn wir den Standardfall beibehalten, wird er überhaupt nicht ausgeführt. Es ist toter Code.

Shiju
quelle
2

Es ist eine optionale Codierungskonvention. Abhängig von der Verwendung ist, ob es benötigt wird oder nicht. Ich persönlich glaube, wenn Sie es nicht brauchen, sollte es nicht da sein. Warum etwas hinzufügen, das vom Benutzer nicht verwendet oder erreicht wird?

Wenn die Fallmöglichkeiten begrenzt sind (dh ein Boolescher Wert), ist die Standardklausel redundant !

Danny Mahoney
quelle
2

Wenn eine switchAnweisung keinen Standardfall enthält , kann das Verhalten unvorhersehbar sein, wenn dieser Fall zu einem bestimmten Zeitpunkt auftritt, der in der Entwicklungsphase nicht vorhersehbar war. Es ist eine gute Praxis, einen defaultFall aufzunehmen.

switch ( x ){
  case 0 : { - - - -}
  case 1 : { - - - -}
}

/* What happens if case 2 arises and there is a pointer
* initialization to be made in the cases . In such a case ,
* we can end up with a NULL dereference */

Eine solche Vorgehensweise kann zu einem Fehler wie NULL-Dereferenzierung , Speicherverlust sowie anderen Arten schwerwiegender Fehler führen .

Zum Beispiel nehmen wir an, dass jede Bedingung einen Zeiger initialisiert. Wenn jedoch ein defaultFall auftreten soll und wir in diesem Fall nicht initialisieren, besteht jede Möglichkeit, mit einer Nullzeigerausnahme zu landen. Daher wird empfohlen, eine defaultcase-Anweisung zu verwenden, auch wenn diese möglicherweise trivial ist.

Trevor
quelle
2

Der Standardfall ist in dem von enum verwendeten Switch möglicherweise nicht erforderlich. Wenn der Schalter alle Werte enthielt, wird der Standardfall niemals ausgeführt. In diesem Fall ist dies also nicht erforderlich.

iOkay
quelle
1

Hängt davon ab, wie der Switch in einer bestimmten Sprache funktioniert. In den meisten Sprachen wird die Ausführung jedoch ohne Warnung durch die switch-Anweisung geleitet, wenn kein Fall übereinstimmt. Stellen Sie sich vor, Sie haben eine Reihe von Werten erwartet und diese im Schalter behandelt, erhalten jedoch einen anderen Wert in der Eingabe. Nichts passiert und Sie wissen nicht, dass nichts passiert ist. Wenn Sie den Fall in Verzug geraten, wissen Sie, dass etwas nicht stimmt.

Gabriel Ščerbák
quelle
1

Ich bin mit der oben am häufigsten gewählten Antwort von Vanwaril nicht einverstanden.

Jeder Code erhöht die Komplexität. Auch Tests und Dokumentationen müssen dafür durchgeführt werden. Es ist also immer gut, wenn Sie mit weniger Code programmieren können. Meiner Meinung nach verwende ich eine Standardklausel für nicht erschöpfende switch-Anweisungen, während ich keine Standardklausel für erschöpfende switch-Anweisungen verwende. Um sicherzugehen, dass ich das richtig gemacht habe, verwende ich ein statisches Code-Analyse-Tool. Gehen wir also auf die Details ein:

  1. Nicht erschöpfende switch-Anweisungen: Diese sollten immer einen Standardwert haben. Wie der Name schon sagt, handelt es sich um Aussagen, die nicht alle möglichen Werte abdecken. Dies ist möglicherweise auch nicht möglich, z. B. eine switch-Anweisung für einen ganzzahligen Wert oder für einen String. Hier möchte ich das Beispiel von Vanwaril verwenden (Es sollte erwähnt werden, dass er dieses Beispiel verwendet hat, um einen falschen Vorschlag zu machen. Ich verwende es hier, um das Gegenteil zu sagen -> Verwenden Sie eine Standardanweisung):

    switch(keystroke)
    {
      case 'w':
        // move up
      case 'a':
        // move left
      case 's':
        // move down
      case 'd':
        // move right
      default:          
        // cover all other values of the non-exhaustive switch statement
    }
    

    Der Spieler kann jede andere Taste drücken. Dann konnten wir nichts tun (dies kann im Code nur durch Hinzufügen eines Kommentars zum Standardfall angezeigt werden) oder es sollte zum Beispiel etwas auf dem Bildschirm gedruckt werden. Dieser Fall ist möglicherweise relevant.

  2. Vollständige switch-Anweisungen: Diese switch-Anweisungen decken alle möglichen Werte ab, z. B. eine switch-Anweisung für eine Aufzählung von Gradsystemtypen. Bei der ersten Codeentwicklung ist es einfach, alle Werte abzudecken. Da wir Menschen sind, besteht jedoch eine geringe Chance, einige zu vergessen. Wenn Sie später einen Aufzählungswert hinzufügen, sodass alle switch-Anweisungen angepasst werden müssen, um sie wieder vollständig zu machen, wird der Pfad zur Fehlerhölle geöffnet. Die einfache Lösung ist ein statisches Code-Analyse-Tool. Das Tool sollte alle switch-Anweisungen überprüfen und prüfen, ob sie vollständig sind oder einen Standardwert haben. Hier ein Beispiel für eine vollständige switch-Anweisung. Zuerst brauchen wir eine Aufzählung:

    public enum GradeSystemType {System1To6, SystemAToD, System0To100}
    

    Dann brauchen wir eine Variable dieser Aufzählung wie GradeSystemType type = .... Eine vollständige switch-Anweisung würde dann folgendermaßen aussehen:

    switch(type)
    {
      case GradeSystemType.System1To6:
        // do something
      case GradeSystemType.SystemAToD:
        // do something
      case GradeSystemType.System0To100:
        // do something
    }
    

    Wenn wir also GradeSystemTypebeispielsweise um erweitern, sollte System1To3das statische Code-Analyse-Tool erkennen, dass es keine Standardklausel gibt und die switch-Anweisung nicht vollständig ist, sodass wir sicher sind.

Nur eine zusätzliche Sache. Wenn wir immer eine defaultKlausel verwenden, kann es vorkommen, dass das statische Code-Analyse-Tool keine erschöpfenden oder nicht erschöpfenden switch-Anweisungen erkennen kann, da es die defaultKlausel immer erkennt . Dies ist sehr schlecht, da wir nicht informiert werden, wenn wir die Aufzählung um einen anderen Wert erweitern und vergessen, sie einer switch-Anweisung hinzuzufügen.

Asche
quelle
0

Sollten switch-Anweisungen immer eine Standardklausel enthalten? Ohne Standardfall können keine Switch-Fälle existieren. Im Switch-Fall löst der Standardfall switch(x)in diesem Fall den Switch-Wert x aus, wenn er nicht mit anderen Fallwerten übereinstimmt.

Nisal Edu
quelle
0

Ich glaube, das ist ziemlich sprachspezifisch und für den C ++ - Fall ein kleiner Punkt für Enum-Klasse . Welches scheint sicherer als traditionelle C enum. ABER

Wenn Sie sich die Implementierung von std :: byte ansehen, ist es ungefähr so:

enum class byte : unsigned char {} ;

Quelle: https://en.cppreference.com/w/cpp/language/enum

Und bedenken Sie auch Folgendes:

Andernfalls, wenn T ein Aufzählungstyp ist, der entweder einen Gültigkeitsbereich hat oder nicht mit einem festen zugrunde liegenden Typ versehen ist, und wenn die Klammer-Init-Liste nur einen Initialisierer enthält und wenn die Konvertierung vom Initialisierer zum zugrunde liegenden Typ nicht einschränkend ist, und wenn Bei der Initialisierung handelt es sich um eine Direktlisteninitialisierung. Anschließend wird die Aufzählung mit dem Ergebnis der Konvertierung des Initialisierers in den zugrunde liegenden Typ initialisiert.

(seit C ++ 17)

Quelle: https://en.cppreference.com/w/cpp/language/list_initialization

Dies ist ein Beispiel für eine Enum-Klasse, die Werte darstellt, die nicht als Enumerator definiert sind. Aus diesem Grund können Sie Enums nicht vollständig vertrauen. Je nach Anwendung kann dies wichtig sein.

Ich mag jedoch sehr, was @Harlan Kassler in seinem Beitrag gesagt hat, und werde diese Strategie in einigen Situationen selbst anwenden.

Nur ein Beispiel für eine unsichere Enum-Klasse:

enum class Numbers : unsigned
{
    One = 1u,
    Two = 2u
};

int main()
{
    Numbers zero{ 0u };
    return 0;
}
David Ledger
quelle