2008-10-09 28 views
77

Od tak dawna, jak pamiętam, uniknąłem użycia instrukcji switch switchththrough. Właściwie to nie pamiętam, żeby kiedykolwiek wszedł do mojej świadomości jako możliwy sposób robienia rzeczy, jak to było wcześnie wywiercone w mojej głowie, że był niczym więcej jak błędem w instrukcji switch. Jednak dzisiaj natknąłem się na jakiś kod, który używa go z założenia, co sprawiło, że natychmiast zastanawiałem się, co wszyscy w społeczności myślą o przełomie w przełączaniu.Switch Statement Fallthrough ... czy powinno być dozwolone?

Czy jest to coś, na co język programowania wyraźnie nie powinien zezwalać (jak robi C#, ale zapewnia obejście) lub czy jest to funkcja dowolnego języka, który jest wystarczająco silny, aby pozostawić go w rękach programisty?

Edytuj: Nie byłem wystarczająco konkretny, co miałem na myśli przez przełom. Używam tego typu dużo:

switch(m_loadAnimSubCt){ 
     case 0: 
     case 1: 
      // Do something 
      break; 
     case 2: 
     case 3: 
     case 4: 
      // Do something 
      break; 
    } 

Jednak jestem zaniepokojony czymś takim.

switch(m_loadAnimSubCt){ 
     case 0: 
     case 1: 
      // Do something but fall through to the other cases 
      // after doing it. 
     case 2: 
     case 3: 
     case 4: 
      // Do something else. 
      break; 
    } 

W ten sposób, gdy przypadek ma wartość 0, 1, spowoduje to wszystko w instrukcji przełączania. Widziałem to z założenia i po prostu nie wiem, czy zgadzam się, że instrukcje przełączania powinny być używane w ten sposób. Myślę, że pierwszy przykład kodu jest bardzo przydatny i bezpieczny. Drugi wydaje się niebezpieczny.

+0

dupe http://stackoverflow.com/questions/174155/switch-statement-fallthrough-in-c?lq=1 – nawfal

+26

Nie zgadzam się co do braku konstruktywności. 27 głosów na temat tego pytania mówi, że są inni, którzy tak czują. –

+1

"nie jest konstruktywny" to stary i nieco niejasny powód. W dzisiejszych czasach takie pytania mogą i powinny być oznaczane jako zamknięcia wyłącznie jako oparte na opiniach. SO to odpowiedzi na pytania dotyczące kodu lub projektu, a nie "jaka jest opinia" społeczności "[cokolwiek to jest] o mojej opinii na temat funkcji X". Programmingers.SE byłby lepszym rozwiązaniem, ale nawet wtedy wartość tak szerokiego i opartego na opiniach pytania jest nadal wysoce wątpliwa. –

Odpowiedz

65

Może to zależeć od tego, co uważasz za przełom. Jestem ok z tego typu rzeczy:

switch (value) 
{ 
    case 0: 
    result = ZERO_DIGIT; 
    break; 

    case 1: 
    case 3: 
    case 5: 
    case 7: 
    case 9: 
    result = ODD_DIGIT; 
    break; 

    case 2: 
    case 4: 
    case 6: 
    case 8: 
    result = EVEN_DIGIT; 
    break; 
} 

Ale jeśli masz etykiety case następnie kodu, który spada przez wytwórnię do innej sprawy, ja prawie zawsze brać pod uwagę, że zło. Być może lepszym pomysłem byłoby przeniesienie wspólnego kodu do funkcji i wywołanie z obu miejsc.

I proszę pamiętać, że używam definicji "evil"

+0

Zgadzam się z tobą: Nie uważam twojego przykładu za przełom i jeśli istnieje przypadek, w którym chcę wykonać wiele bloków kodu przez przejście, prawdopodobnie jest lepszy sposób –

+4

+1 po prostu dla tej definicji "zła" Pożyczę to, dzięki ;-) –

+0

Dostaję twój punkt i masz rację, ale twój przykład jest naprawdę zły. Nikt nie powinien testować takich cyfr testu. Scnr, twoja odpowiedź i tak jest słuszna. –

17

Przełom jest naprawdę przydatny, w zależności od tego, co robisz. Rozważ ten zgrabny i zrozumiały sposób aranżacji opcji:

switch ($someoption) { 
    case 'a': 
    case 'b': 
    case 'c': 
    // do something 
    break; 
    case 'd': 
    case 'e': 
    // do something else 
    break; 
} 

Wyobraź sobie, że robisz to z if/else. To byłby bałagan.

+0

Uważam ten rodzaj przełomu za bardzo pomocny –

4

Mocny i niebezpieczny. Największym problemem z upadkiem jest to, że nie jest to jednoznaczne. Na przykład, jeśli natkniesz się na często edytowany kod, który ma przełącznik z upadkami, skąd wiesz, że jest to zamierzone, a nie błąd?

Wszędzie go używać, mogę zagwarantować, że to właściwie powiedział:

switch($var) { 
    case 'first': 
     // fall-through 
    case 'second': 
     i++; 
     break; 
} 
+1

Intencja jest oczywista, jeśli nie ma kodu dla przypadku "pierwszy". Jeśli tam kodujesz, a także chcesz uruchomić kod dla sprawy "second", to komentarz jest ważny. Ale i tak uniknęłbym tego scenariusza. –

+0

@Joel - Zgadzam się całkowicie. W moim sklepie, w takich przypadkach ludzie wstawiali się w dół, chociaż komentarze, i myślę, że zmniejsza to czytelność. Jeśli jednak istnieje tam kod, wstaw komentarz. –

14

Słyszałeś o Duff's device? Jest to świetny przykład wykorzystania przełomu w przełączaniu.

Jest to funkcja, której można używać i którą można nadużywać, podobnie jak prawie wszystkie funkcje językowe.

+0

Dowiedz się czegoś nowego każdego dnia - dzięki! Czuję się jednak dla biednych twórców, którzy przechodzą przez takie kontrowersje. –

+0

Wow, to jest coś, co otoczy twój mózg. – Fostah

+3

Uwaga Przytaczany komentarz Duffa w tym artykule: "Ten kod stanowi pewnego rodzaju argument w tej debacie, ale nie jestem pewien, czy jest za czy przeciw." –

0

W niektórych przypadkach wykorzystanie upadków jest aktem lenistwa ze strony programisty - mogliby użyć serii || na przykład, ale zamiast tego użyj serii "przełączników".

To powiedziawszy, znalazłem je szczególnie pomocne, gdy wiem, że ostatecznie I tak będę potrzebować opcji (na przykład w odpowiedzi menu), ale jeszcze nie wdrożyłem wszystkich opcji . Podobnie, jeśli robisz fall-through zarówno dla "a" i "A", uważam, że znacznie czystsze jest użycie przełącznika fall-through niż instrukcji złożonej, jeśli.

To pewnie kwestia stylu i sposobu myślenia programistów, ale ogólnie nie lubię usuwania komponentów języka w imię "bezpieczeństwa" - dlatego dążę do C i jego wariantów/potomków więcej niż, powiedzmy, Java. Lubię być w stanie małpować ze wskaźnikami i tym podobnymi, nawet gdy nie mam "powodu".

+0

Ściśle mówiąc. Instrukcje switch przeskakują przez ustawioną wartość do wiązki określonych lokalizacji kodu. Podczas, gdy kompilator prawdopodobnie złapie takie rzeczy, istnieje wartość prędkości i poprawności do instrukcji switch na szeregu instrukcji lub instrukcji. Jeśli p wynosi 0 lub p wynosi 1 lub p wynosi 2. Musiałem właściwie ocenić, czy p wynosiło 0, a p 1, zamiast przeskakiwać do miejsca p = 2 w kodzie. Które stało się identyczne z p0 i p1. Ale nigdy nie musiałem ich sprawdzać. – Tatarize

5

Podobnie jak wszystko: ostrożnie używane może być eleganckim narzędziem.

Jednak, moim zdaniem, wady bardziej niż uzasadniają NIE używanie go, a na koniec, aby już go nie dopuścić (C#). Wśród problemów są:

  • łatwo „zapomnieć” przerwę
  • nie zawsze jest oczywista dla opiekunów kodowych, że pominięto przerwa była zamierzona

dobry użycie przełącznika/obudowy fallthrough:

switch (x) 
{ 
case 1: 
case 2: 
case 3: 
do something 
break; 
} 

użycie BAAAAAD przełącznika/obudowy fallthrough:

switch (x) 
{ 
case 1: 
    some code 
case 2: 
    some more code 
case 3: 
    even more code 
    break; 
} 

To może być przepisane przy użyciu if/else konstruuje bez utraty w mojej opinii.

Moje ostatnie słowo: trzymaj się z daleka od przypadkowych etykiet na okładkach, jak w przykładzie ZŁY, chyba że zachowujesz starszą wersję kodu, w której ten styl jest używany i dobrze zrozumiany.

+1

Możesz przepisać większość konstrukcji językowych za pomocą if() i goto ... nie uzasadnia to jednak rezygnacji z jawnej konstrukcji. – Shog9

+2

Wiem, ale przełączniki/konstrukcje skrzynek, które jawnie używają "przypadku 1: jakiś kod przypadku 2: trochę więcej kodu 3: ostateczny podział kodu;" może i powinien być przepisany przy użyciu if/else if (my opinion). – steffenj

41

To miecz obosieczny. Czasami bardzo przydatne, często niebezpieczne.

Kiedy to jest dobre? Gdy chcesz 10 przypadków wszystkie zrealizowane w ten sam sposób ...

switch (c) { 
    case 1: 
    case 2: 
      ... do some of the work ... 
      /* FALLTHROUGH */ 
    case 17: 
      ... do something ... 
      break; 
    case 5: 
    case 43: 
      ... do something else ... 
      break; 
} 

Jedna zasada Lubię to, że jeśli kiedykolwiek zrobić niczego wyjątkowego, gdzie wyklucza przerwy, trzeba wyraźny komentarz/* fallthrough */do wskazać, że to była twoja intencja.

+2

+1! Zgadzam się, że jest to od czasu do czasu właściwa odpowiedź, i W DOKŁADNIE zgadzam się, że gdy jest ona zaprojektowana, powinna zostać skomentowana. (W recenzji kodu, chciałbym, aby inny komentarz dewelopera nie był pustym projektem typu fall-through, ale nie jest to sklep z C#, który nie jest obsługiwany :) –

+4

Sam używam/* FALL PRZEZ */skomentuj w moim kodzie, w razie potrzeby. =] – strager

+1

Jeśli masz PC-Lint, musisz wstawić/* - fallthrough * /, w przeciwnym razie narzeka. –

2

Nie podoba mi się, że moje oświadczenia switch przez to przechodzą - są zbyt podatne na błędy i trudne do odczytania. Jedynym wyjątkiem jest sytuacja, gdy wiele instrukcji case robi dokładnie to samo.

Jeśli istnieje jakiś wspólny kod, którego chcesz użyć w wielu gałęziach instrukcji switch, wyodrębniam ją do oddzielnej wspólnej funkcji, którą można wywołać w dowolnej gałęzi.

9

C++ FAQ To może być bardzo przydatna kilka razy, ale w ogóle, no-fallthrough jest pożądane zachowanie. Przełom powinien być dozwolony, ale nie ukryty.

Przykładem, aby aktualizować stare wersje niektórych danych:

switch (version) { 
    case 1: 
     // update some stuff 
    case 2: 
     // update more stuff 
    case 3: 
     // update even more stuff 
    case 4: 
     // and so on 
} 
1

upadek myśli powinny być stosowane tylko wtedy, gdy jest on używany jako stół skoczyć do bloku kodu.Jeśli jest jakaś część kodu z bezwarunkową przerwą przed kolejnymi przypadkami, wszystkie grupy spraw powinny zakończyć się w ten sposób. Wszystko inne jest "złe".

6

chciałbym inną składnię fallbacks w rozjazdach, coś, eeee ..

switch(myParam) 
{ 
    case 0 or 1 or 2: 
    // do something; 
    break; 
    case 3 or 4: 
    // do something else; 
    break; 
} 

Uwaga: to byłoby już możliwe teksty stałe, jeśli zadeklarować wszystkie przypadki na swoim enum przy użyciu flagi dobrze? Czyż nie brzmi to tak źle, że przypadki mogłyby (powinny?) Bardzo dobrze być już częścią twojego wyliczenia.

Może to byłby miły przypadek (gra słów nie przeznaczonych) dla płynnego interfejsu przy użyciu metod rozszerzenia? Coś podobnego, eeee ...

int value = 10; 
value.Switch() 
    .Case(() => { /* do something; */ }, new {0, 1, 2}) 
    .Case(() => { /* do something else */ } new {3, 4}) 
    .Default(() => { /* do the default case; */ }); 

Chociaż to chyba nawet mniej czytelny: P

+1

Bardzo podoba mi się pierwsza sugestia. To bardzo dobrze się czyta i zapisuje kilka linijek kodu. Druga zajęła minutę, aby zawinąć mózg, ale ma sens, ale wygląda na zagmatwany. – Fostah

+1

Tak, to też myślałem, to był tylko przypadkowy przypadek, który odłożyłem, starając się znaleźć inny sposób przełączania się przy użyciu istniejących konstrukcji językowych. –

+0

Przeszedłem przez to pytanie i naprawdę to lubię! Miałem pomysł, jak poprawić czytelność tego, ale SO nie pozwala mi publikować komentarzy wielowierszowych :( Ktoś powinien wdrożyć to tak jak POC, wygląda zabawnie do wdrożenia i użycia (: –

2

Korzystanie spadek przelotowe jak w pierwszym przykładzie jest wyraźnie OK, nie uważam, że jest to prawdziwy upadek-through.

Drugi przykład jest niebezpieczny i (jeśli nie komentowany obszernie) nie jest oczywisty. Uczę moich uczniów, aby nie używali takich konstrukcji, O ile uważają, że warto poświęcić temu blokowi komentarz, który opisuje, że jest to celowy przełom i dlaczego to rozwiązanie jest lepsze niż alternatywy. Odradza to niechlujstwo, ale nadal pozwala na to w przypadkach, w których jest wykorzystywany na korzyść.

To mniej więcej tyle samo, co robiliśmy w projektach kosmicznych, gdy ktoś chciał złamać standard kodowania: musieli wystąpić o zwolnienie (i zostałem wezwany do udzielenia porady w sprawie orzeczenia).

Powiązane problemy