Switchステートメントのフォールスルー…許可されるべきか?[閉まっている]


120

覚えている限り、switchステートメントのフォールスルーの使用は避けてきました。実際、switchステートメントのバグにすぎないということを、頭の中で掘り下げたため、可能なこととして意識の中に入るのを思い出すことはできません。しかし、今日、私はそれを仕様で使用するコードに出くわしました。そのため、コミュニティの誰もがswitchステートメントのフォールスルーについて何を考えているのかすぐに気になりました。

それはプログラミング言語が明示的に許可してはいけないものですか(C#のように、回避策を提供します)、それともプログラマーの手に委ねるのに十分強力な言語の機能ですか?

編集: 私はフォールスルーで何を意味するのか十分に特定していませんでした。私はこのタイプをよく使います:

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

しかし、私はこのようなことが心配です。

   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;
   }

このように、ケースが0、1の場合は常に、switchステートメントのすべてを実行します。これは仕様で見たことがありますが、switchステートメントをこのように使用する必要があることに同意するかどうかはわかりません。最初のコード例は非常に便利で安全だと思います。2番目は一種の危険なようです。



51
建設的でないことについては同意しません。質問に対する27の賛成票は、このように感じる人もいると言っています。
Wesモード

2
「建設的でない」というのは、古くて漠然とした近い理由です。現在、このような質問は、純粋に意見に基づくものとして、閉鎖のフラグを立てることができます。SOはコードやデザインに関する答えのある質問のためのものであり、「フィーチャーXについての私の意見についての「コミュニティ」の意見は何ですか」という意味ではありません。Programmers.SEの方が適していますが、それでも、このように幅広い意見に基づく質問の価値は依然として非常に疑わしいものです。
underscore_d

1
フォールスルーが使用されている非常に明確なユースケースがあるので、なぜそれが意見に基づくのかわからない。この質問は少し不明確であることに同意しますが、建設的ではないので閉じるべきではありませんでした。「フォールスルーはいつ使用されますか?」というより明確なケースになるように編集しただけかもしれません。明確な答えがあります。良いC ++テキストはこれを乗り越え、新しいプログラマー(または他の言語の経験豊富なプログラマー)を混乱させるので、SOにとって良い質問のようです。確かに、それはプロトタイプ的に良いSOの質問のようです。それが尋ねられた方法が完璧でなかったとしても。
エリック2018

回答:


89

それはあなたがフォールスルーと考えるものに依存するかもしれません。私はこの種のもので大丈夫です:

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;
}

しかし、ケースラベルに続いて別のケースラベルに分類されるコードがある場合、私はほとんど常にその悪を考慮します。おそらく、共通のコードを関数に移動し、両方の場所から呼び出すほうがよいでしょう。

また、「悪」のC ++ FAQ定義を使用していることに注意してください


私はあなたに同意します。私はあなたの例をフォールスルーとは考えていません。フォールスルーを介して複数のコードブロックを実行したい場合は、おそらくより良い方法があります。
Dave DuPlantis 2008年

10
+1は、単に「悪」の定義を表します。私はそれを借ります、ありがとう;-)
ヨアヒムザウアー

私はあなたのポイントを理解し、あなたは正しいですが、あなたの例は本当に悪いです。誰もこのようなテスト桁をテストするべきではありません。Scnr、とにかくあなたの答えは正しいです。
TimBüthe10年

適切な例として、それはC#で許可されていないことです。理由の可能性が高い:-)
Joey

悲しいことに、悪の定義はオフラインになっているようです
うまくいけば

57

両刃の剣です。それは時々非常に便利ですが、しばしば危険です。

いつおいしい?10個のケースがすべて同じように処理されるようにしたい場合...

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;
}

私が好きなルールの1つは、休憩を除外することで気の利いたことをする場合は、明確なコメント/ * FALLTHROUGH * /が必要であることを示しています。


3
+1!私はそれが時々正しい答えであることに同意します、そしてそれが仕様による場合はコメントされるべきであることに二重に同意します。(コードレビューでは、他の開発者に、空ではないフォールスルーの設計上のコメントをコメントさせます。それは起こりません。これはサポートされていないC#ショップです。)
John Rudy

4
私自身、必要に応じてコードで/ * FALL THROUGH * /コメントを使用しています。=]
ストレッジャー2008

2
PC-Lintの場合、/ *-fallthrough * /を挿入する必要があります。
スティーブメルニコフ2009

1
それでも、動作が意図的なものであることを明確にしたい場合は、if(condition > 1 && condition <10) {condition = 1}; switch(...ケースを節約し(見た目を明確にするため)、それらのケースで同じアクションをトリガーしたいことを誰もが確認できます。
2014

1
これはまだひどいコーディングです。最初のケースは関数を呼び出し、2番目のケースは同じ関数を呼び出してから、2番目の関数を呼び出す必要があります。
BlueRaja-Danny Pflughoeft 2014

21

ダフのデバイスご存知ですか?これは、スイッチフォールスルーを使用する良い例です。

ほとんどすべての言語機能と同様に、これは使用できる機能であり、悪用される可能性があります。


毎日新しいことを学びましょう-ありがとう!私はそのようなゆがみを通り抜ける貧しい開発者たちのために感じます。
ジャスティンR.

うわー、それはあなたの脳を包むかなりのものです。
Fostah 2008年

6
その記事でダフが引用したコメントに注意してください。「このコードはその議論の中で何らかの議論を形成しますが、それが賛成か反対かはわかりません。」
ジョンカーター、

ダフの装置は明らかに悪である
Marjeta

21

フォールスルーは、何をしているのかに応じて、本当に便利なものです。オプションを整理するためのこのきちんとした理解できる方法を検討してください:

switch ($someoption) {
  case 'a':
  case 'b':
  case 'c':
    // Do something
    break;

  case 'd':
  case 'e':
    // Do something else
    break;
}

if / elseでこれを行うことを想像してください。混乱するでしょう。


1
このタイプのフォールスルーは非常に役立つと思います
Mitchel Sellers

もし「何かをする」がスイッチより少しだけ多い場合は、むしろif / elseよりも混乱します。if / elseを使用すると、どの変数をテストするかがどこでも明確になります。この小さな例でも、if / elseが私の目にはそれほど悪くはありません
グレニック2018

10

これは非常に便利な場合もありますが、通常、フォールスルーが目的の動作になることはありません。フォールスルーは許可されるべきですが、暗黙的ではありません。

一部のデータの古いバージョンを更新する例:

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

6

スイッチのフォールバックの別の構文が好きです。

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

注:フラグを使用して列挙型のすべてのケースを宣言する場合、これは列挙型ですでに可能です。それもそれほど悪く聞こえません。ケースはすでにあなたの列挙型の一部である可能性があります(すべきですか?)。

たぶん、これは拡張メソッドを使用する流暢なインターフェースの良い例です(しゃれは意図されていません)。えっと…

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

それはおそらくもっと読みにくいですが:P


1
最初の提案はとても気に入っています。これは非常に読みやすく、数行のコードを節約できます。2番目は私の脳を包み込むのに1分かかりましたが、理にかなっていますが、混乱しているように見えます。
フォスタ09

1
ええ、それも私が考えていたものです。それは、既存の言語構造を使用して切り替える別の方法を見つけるための、私が下に置いた無作法な心のおならでした。
エリックファンブラケル

この質問を実行すると、私は実際にこれが好きです!これの読みやすさを向上させる方法に関するアイデアがありましたが、SOは複数行のコメントを投稿することを許可していません:(誰かがこれをPOCとして実装する必要があり、実装して使用するのが楽しいようです(:
Victor Elias

5

何でもそうです:注意して使用すると、エレガントなツールになります。

しかし、欠点はそれを使用しないことを正当化すること、そして最後にそれをもう許可しないこと(C#)よりも多いと思います。問題の中には:

  • 休憩を「忘れる」のは簡単です
  • コードメンテナーにとって、省略された改行が意図的なものであることは必ずしも明白でありません

スイッチ/ケースのフォールスルーの活用:

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

スイッチ/ケースのフォールスルーのBaaaaadの使用:

switch (x)
{
case 1:
    Some code
case 2:
    Some more code
case 3:
    Even more code
    break;
}

これは、私の見解では、損失のないif / else構文を使用して書き換えることができます。

私の最後の言葉:このスタイルが使用され、よく理解されているレガシーコードを維持しているのでない限り、悪い例のようにフォールスルーケースラベルに近づかないでください。


3
ほとんどの言語構成は、if()とgotoを使用して書き直すことができますが、明示的な構成を放棄することを正当化するものではありません。
Shog9 2008年

2
私は知っていますが、「ケース1:いくつかのコードケース2:いくつかのコードケース3:最終的なコードブレーク」を明示的に使用するスイッチ/ケースコンストラクト。if / else if(私の意見)を使用して書き換えることができます。
steffenj 2008年

1
スイッチは、if-elsesのリストよりも何倍も高速になる可能性があることに注意してください。Switchはジャンプテーブルを使用します。それが不可能な場合は、条件付きジャンプの線形リストではなく、条件付きジャンプがディシジョンツリーで構造化されます。適切に構造化されたネストされたIf-elseステートメントは、せいぜい同等に高速です。
Jochem Kuijpers、2018

4

それは強力で危険です。フォールスルーの最大の問題は、明示的ではないことです。たとえば、フォールスルーのあるスイッチを持つ頻繁に編集されるコードに遭遇した場合、それが意図的なものであり、バグではないことをどのようにして知るのでしょうか。

私がそれを使用するときはいつでも、適切にコメントされていることを確認します。

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

2
ケース 'first'のコードがない場合、その意図は明白です。そこにコードを記述し、大文字と小文字を区別してコードを実行したい場合は、コメントが重要です。しかし、私はとにかくそのシナリオを避けます。
Joel Coehoorn、2008年

1
@ジョエル-私は完全に同意します。私の店では、そういう場合に落ち込んでコメントを入れていただいているので、読みやすさを損なうと思います。ただし、そこにコードがある場合は、フォールスルーコメントを入力します。
Fred Larson、

「明示的ではない」とはどういう意味ですか。これが私たちが破る理由です。他の言語がこれを行います。それは順番に言語を学んでいない人にとってのみ問題です。C#は、デフォルトのケースffsに対して、imhoする理由なしにそれを要求します。
mckenzm

3

最初の例のようにフォールスルーを使用することは明らかにOKであり、実際のフォールスルーとは見なしません。

2番目の例は危険であり、(広範囲にコメントされていない場合)自明ではありません。私はこのような構築物を使用しないように私の学生を教えていない限りコメントブロックを捧げる努力をする価値があると考え、これは、これが意図的なフォールスルーであり、このソリューションが他の方法より優れている理由を説明しています。これはずさんな使用を思いとどまらせますが、それが有利に使用される場合でもそれを許可します。

これは、だれかがコーディング標準に違反することを望んだときに宇宙プロジェクトで行ったのとほぼ同じです。彼らは、認可を申請しなければなりませんでした(そして、裁定について助言を求められました)。


2

自分のswitch発言が失敗するのは好きではありません。エラーが発生しやすく、読みにくいです。唯一の例外は、複数のcaseステートメントがすべて正確に実行される場合です。同じことをです。

switchステートメントの複数のブランチで使用したい共通コードがある場合は、それを任意のブランチで呼び出すことができる個別の共通関数に抽出します。


1

場合によっては、フォールスルーの使用は、プログラマー側の怠惰な行為です。一連の||を使用できます。ステートメントなどですが、代わりに一連の「キャッチオール」スイッチケースを使用します。

そうは言っても、結局それがわかっているときは特に役立つことがわかりました私は(メニュー応答、例えば)とにかくオプションを必要とするつもりですが、まだすべての選択肢を実装していません。同様に、「a」と「A」の両方でフォールスルーを実行している場合、複合ifステートメントよりもスイッチフォールスルーを使用する方がはるかにクリーンです。

それはおそらくスタイルとプログラマーの考え方の問題ですが、私は一般に「安全」の名のもとに言語のコンポーネントを削除するのが好きではありません。 Java。「理由」がないときでも、ポインタなどでモンキーアラウンドができるのが好きです。


厳密に言えば。switchステートメントは、設定値を介して一連の特定のコード位置にジャンプします。コンパイラーはそのようなことをキャッチする可能性が高いですが、一連のorステートメントに対するswitchステートメントの速度と正確さの値があります。pが0またはpが1またはpが2の場合、コードでp = 2の場所にジャンプするのではなく、pが0であるかpが1であるかを実際に評価する必要がありました。これはたまたまp0とp1と同じでした。しかし、私はそれらをチェックする必要はありませんでした。
酒石化

1

フォールスルーは、コードブロックへのジャンプテーブルとして使用する場合にのみ使用してください。より多くのケースの前に無条件のブレークがあるコードの部分がある場合、すべてのケースグループはそのように終了する必要があります。

それ以外は「悪」です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.