11

列挙型があるとしましょう。

enum class ShapeName : char {TRIANGLE,CIRCLE,SQUARE};

そして後で私はこのような機能を持っています:

void Function (ShapeName const shape){

    switch (shape){
        case ShapeName::TRIANGLE:
            DoSomething1();
            break;

        case ShapeName::CIRCLE:
            DoSomething2();
            break;

        case ShapeName::SQUARE: 
            DoSomething3();
            break;

        default:
            //THIS CODE BLOCK SHOULD NEVER BE EXECUTED!
    }

    return;
}

デフォルトのラベルは決して実行されるべきではありませんが、プログラマーが「ShapeName」に別の値を追加し、それがスイッチで考慮されていない場合に発生する可能性のある潜在的なバグを説明したいと思います。
あなたは私に何を勧めますか?

1.アサーションアサーション
を使用できますが、何をアサーションしていますか?

assert(false); //?

2.例外例外
をスローすることはできますが、それはあまり良い習慣ではないと思います。例外は、特定の環境のために予測できない実行時イベントに対するものであるという印象を受けています。

3.
終了エラーが発生した場合、プログラムをすぐに終了できます。それは最良のアイデアのように感じますが、それが良い習慣かどうかはわかりません。アサーションの利点は、プログラムを出荷する準備ができたときにすべてオフにできることだと思いました。そうすると、そのアサーションコードはすべて存在しなくなります。


多分私が気付いていない別の方法があります。未考慮の値について警告するコンパイラフラグを使用しますが、それでも他の人が推奨するものを知りたいです。

4

4 に答える 4

9

私は有益なメッセージで主張するという考えが好きです。これを試して:

assert (!"The default case of so-so switch was reached.");

これは常にfalseを返しますが、使用できるメッセージを提供します。

編集:
私はこの概念を私の記憶から引き出したソースを見つけました。それは次の本にあります:
C++コーディング標準-101ルールとガイドライン

于 2012-04-28T02:24:10.197 に答える
4

列挙型タグをオンにしてすべてのケースを処理するこの特定のケースに対する私の好みは、デフォルトを除外することです。そうすれば、適切なコンパイラを使用して、誰かがスイッチではなく列挙型に新しいタグを追加すると、スイッチでタグが処理されていないことに関するコンパイル時の警告が表示されます。

于 2012-04-28T02:32:40.670 に答える
0

私にとっては、DoSomething#メソッドが何をするかに多少依存すると思います。

後であまり優雅でないクラッシュが発生する場合は、「無効な列挙型:enumNameで呼び出された関数」の説明などで呼び出されたときにランタイムを中断し、開発者にこのswitchステートメントを更新しなかったことを通知します。後で何かが失敗するかどうか疑問に思うままにするのではなく。

于 2012-04-28T02:27:28.417 に答える
0

簡単な答え:ポリモーフィズムを使用して問題を排除します。

長い答え:根本的な問題(つまり、エントリが欠落しているswitchステートメントを防ぐ方法)を解決する最も簡単な方法は、エントリが忘れられる可能性がある場合にswitchステートメントの使用を避けることです。Switchステートメントはローカルコンテキストで役立ちますが、それらが表すロジックが複数の場所で重複している場合は、1つを更新するのを忘れる可能性があり、ランタイムエラーに備えることになります。

class Shape
{
    // functionality MUST be added for new shape types
    // or a compile error will occur
    virtual void DoSomething() const = 0;
};

void Function (Shape const & shape){
    return shape.DoSomething();
}

switchステートメントは、作成サイトで引き続き役立つ場合があります。

enum class ShapeName : char {TRIANGLE,CIRCLE,SQUARE};

unique_ptr< Shape > MakeShape (ShapeName const shape){
    switch (shape){
        case ShapeName::TRIANGLE:
            return unique_ptr< Shape >( new Triangle() );

        case ShapeName::CIRCLE:
            return unique_ptr< Shape >( new Circle() );

        case ShapeName::SQUARE: 
            return unique_ptr< Shape >( new Square() );
     }

     throw std::runtime_error();
     // or whichever option you prefer from the other answers
}

しかし、それがロジックが存在する唯一の場所です。そしてそれでさえ、静的ポリモーフィズムで改善することができます:

enum class ShapeName : char {TRIANGLE,CIRCLE,SQUARE,ELLIPSE};

template< ShapeName shape >
unique_ptr< Shape > MakeShape();

template<>
unique_ptr< Shape > MakeShape< ShapeName::TRIANGLE >()
{
    return unique_ptr< Shape >( new Triangle() );
}

template<>
unique_ptr< Shape > MakeShape< ShapeName::CIRCLE >()
{
    return unique_ptr< Shape >( new Circle() );
}

template<>
unique_ptr< Shape > MakeShape< ShapeName::SQUARE >()
{
    return unique_ptr< Shape >( new Square() );
}

int main()
{
    MakeShape< ShapeName::TRIANGLE >(); // okay

    MakeShape< ShapeName::ELLIPSE >(); // compile error
}

詳細については、 MartinFolwerを参照してください。

于 2012-04-28T11:30:58.710 に答える