打开枚举时编译器警告

时间:2011-05-09 10:34:14

标签: c++ visual-c++-2008

enum ENUM(Option1,Option2,Option3);

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

这会编译并运行但会给出编译器警告,并非所有控制路径都会返回。但是,如果你正确使用枚举,那不是这样的吗?如果添加了另一个ENUM val,我希望编译失败,但只要涵盖所有情况,我希望它编译无警告。

这是编译器防止坏的值,它是否只是C ++的一部分并且需要与之共存?

3 个答案:

答案 0 :(得分:7)

在C ++中,枚举并不安全。您不能指望枚举值是枚举声明中定义的值之一:

  • 它可能是未初始化的(因此是垃圾)
  • 您可能来自static_cast
  • int不当

因此,即使您覆盖了枚举的所有元素,编译器也不能指望切换返回。但是,从功能上讲,这确实是一个错误的条件。

有两种方法可以做出反应:

  • default
  • 中添加enum个案
  • 在切换后添加一条语句

为了明智地选择,请记住编译器可能(如果你提出的话)在switch未覆盖enum的所有情况时触发警告,条件是存在default没有default声明。智能编译器(即Clang)允许单独将警告映射到错误,这有助于捕获这些错误。

因此,您决定采取:

  • 如果您希望在更新枚举后忘记更改此方法时收到通知,请不要使用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)") } 宏,它在Debug中引发内存转储(这样我得到一个完整的跟踪)并记录错误并抛出Release(以便服务器停止处理此请求,但是并没有完全停止响应。)

这给出了类似的代码:

{{1}}

答案 1 :(得分:5)

从编译器的角度来看,枚举的类型是一个整数,因此x的值仍然可能是其他情况之一。

通常情况下,我会添加一个触发内部错误的default:标签。

提示:如果在无限循环中包含调用intern错误,则不必创建伪造的返回值。例如:

#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");
 }
}

答案 2 :(得分:3)

如果由于某种原因x既不是Option1,也不是Option2,也不是Option3,会发生什么?

当然,你可以说永远不会发生,但由于该方法必须返回一些东西,你有两种选择:

  • 在最后添加return string("");

  • default添加到返回switch的{​​{1}}。

正如CodeGray指出的那样,第二种选择可以说是更好的风格。你也可以返回一个空字符串以外的东西。