6
enum ENUM(Option1,Option2,Option3);

string func(ENUM x)
{
 switch(x)
 {
  case Option1: return "Option1";
  case Option2: return "Option2";
  case Option3: return "Option3";
 }
}

これはコンパイルして機能しますが、すべての制御パスが返されるわけではないことをコンパイラに警告します。ただし、列挙型を適切に使用すると、そうではないという点ではありませんか?別のENUMvalが追加された場合、コンパイルを失敗させたいのですが、すべてのケースがカバーされている限り、警告なしでコンパイルしたいと思います。

これは、キャストされていない値から保護するコンパイラですか、C ++の一部であり、使用する必要がありますか?

4

3 に答える 3

10

C ++では、列挙型は安全ではありません。enum値がenum宣言で定義された値の1つであると期待することはできません。

  • 初期化されていない可能性があります(したがってゴミ)
  • static_castあなたはから不適切を持っている可能性がありますint

したがって、列挙型のすべての要素をカバーしている場合でも、コンパイラはスイッチが戻ることを期待できません。ただし、機能的には、これは本当にエラー状態です。

反応する方法は2つあります。

  • ケースを追加defaultしますenum
  • 切り替え後にステートメントを追加する

賢明に選択するために、コンパイラは、ステートメントがないという条件で、 aswitchがのすべてのケースをカバーしていないときはいつでも、(あなたがそれを求めれば)警告をトリガーするかもしれないことを覚えておいてください。スマートコンパイラ(つまりClang)を使用すると、警告をエラーに個別にマッピングできるため、これらのバグを見つけるのに非常に役立ちます。enumdefault

したがって、次のことを行う必要があります。

  • 列挙型の更新後にこのメソッドを変更するのを忘れたときに通知を受け取りたい場合は、使用しないでくださいdefault
  • 列挙型を更新してこのスイッチを無視できるようにする場合は、default

最後に、実行時エラーの使用はデフォルトのステートメントの使用と矛盾することに注意して、どのように対応するかを決定する必要があります(可能な限りコンパイル時にエラーをキャッチするのが最善です)。

  • エラーを無視して、事前定義された値を返します
  • 例外をスローします(列挙値を使用してください)
  • アサート(したがって、デバッグで激しくクラッシュし、メモリダンプを取得し、リリースで何もしない、例外をスローするなど、他のことを実行します)

私の個人的なお気に入りはUNREACHABLE(Text_)マクロです。これは、デバッグでメモリダンプを引き起こし(完全なトレースを取得するため)、エラーをログに記録してリリースをスローします(サーバーがこの要求の処理を停止しますが、応答を完全に停止しないようにします)。

これにより、次のようなコードが得られます。

char const* func(ENUM x)
{
 switch(x)
 {
  case Option1: return "Option1";
  case Option2: return "Option2";
  case Option3: return "Option3";
 }
 UNREACHABLE("func(ENUM)")
}
于 2011-05-09T12:41:03.813 に答える
6

コンパイラーの観点からは、列挙型の型は整数であるため、の値がx他の場合の1つである可能性があります。

default:通常、内部エラーをトリガーするラベルを追加します。

ヒント:呼び出しを無限ループでインターンエラーにラップする場合、偽の戻り値を発明する必要はありません。例えば:

#define IntErr(x) for(;;) { InternalError(x); }
string func(ENUM x)
{
  switch(x)
  {
  case Option1: return "Option1";
  case Option2: return "Option2";
  case Option3: return "Option3";
  default: IntErr("Unexpected ENUM value");
 }
}
于 2011-05-09T10:42:27.720 に答える
2

何らかの理由で、でも、でもxない場合はどうなりますか?Option1Option2Option3

確かに、それは決して起こらないと主張することもできますが、メソッドは何かを返す必要があるため、2つのオプションがあります。

  • 最後にを追加しreturn string("");ます。

  • を返すdefaultにを追加します。switchstring("")

CodeGrayが指摘しているように、2番目のオプションは間違いなくより良いスタイルです。空の文字列以外のものを返すこともできます。

于 2011-05-09T10:38:16.637 に答える