2011-05-09 74 views
4
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++的一部分,需要与生活在一起?

+0

尝试添加'default'路径。 – Archie 2011-05-09 10:39:26

+2

@Archie:错误的解决方案,如果你忘记了一个枚举成员,那么你没有警告。 – 2011-05-09 12:27:47

+2

@Matthieu:这不完全是最佳做法。我会一直添加默认值。如果您想要警告您忘记了某个值,请在默认情况下添加断言或抛出异常。编译器不是为了提醒你必须做的事情,而是编译你的代码。 – 2011-05-09 13:08:27

回答

3

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

当然,你可以认为不会发生,但由于该方法返回的东西,你有两个选择:

  • 末增加return string("");

  • switch添加default返回string("")

正如CodeGray指出的那样,第二种选择可以说是更好的风格。您也可以返回除空字符串之外的其他内容。

+0

+1,你需要一个默认的返回值,但我肯定会在最后添加一个'default'的情况。我认为这更具可读性。 – 2011-05-09 10:40:50

+0

你用'return null'表示什么意思?如果你的意思是'NULL',那么你有其他问题,因为'std :: string'不喜欢'NULL'。 – rve 2011-05-09 10:43:10

+0

在C++中,'string'是一个值对象,所以你不能返回一个空指针(顺便说一下,它在C++中被命名为“NULL”)。在这种情况下,您可以使用“”,但是,请参阅我对解决方案的回答,您根本不必发明虚假返回值。 – Lindydancer 2011-05-09 10:44:28

5

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

通常情况下,我会添加一个触发内部错误的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"); 
} 
} 
+0

我没有意识到编译器直接将enums直接插入整数,这确实解释了它......但为什么它首先做到这一点?布尔人是同样对待还是保持自己的类型? – 2011-05-09 14:01:27

+0

无限循环如何提供帮助?假冒伪劣价值比永不完成执行还好吗? – Grault 2015-04-11 15:46:58

+0

@Jesdisciple,它不是一个永不完成的执行,函数'InternalError'停止执行。 'for(;;)'确保你不必写一个“死”的return语句。 – Lindydancer 2015-04-11 19:37:17

3

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

  • 它可以被未初始化(因此垃圾)
  • 你可以从int

有不当static_cast因此,即使覆盖枚举的所有元素,编译器也不能指望返回。但从功能上讲,这确实是一种错误状态。

有两种方式作出反应:

  • 一个default情况下添加到您的enum
  • 添加一条语句开关

为了明智的选择后,请记住,编译器可能(如果你问的话)在switch没有涵盖enum的所有情况下触发警告,条件是没有default声明。智能编译器(即Clang)允许将警告分别映射到错误,这极大地帮助捕获这些错误。

因此,你必须决定采取:

  • 如果你想通知当你忘记更新枚举后,要改变这种方法,那么如果你想成为不使用default
  • 能够更新枚举,并忽略此开关,然后用default

最后,你必须决定如何作出反应,并指出,使用一个运行时错误是使用默认声明不一致的(最好在捕捉错误COM桩时尽可能):

  • 忽略错误并返回一些预定义的值
  • 抛出一个异常(与枚举值,请)
  • 断言(因此崩溃很难在调试,获得内存转储,和做其他事情在发行,像什么,或抛出异常)

我个人的最爱是UNREACHABLE(Text_)宏,它引发的调试内存转储(让我得到一个完整的曲线)和日志一个错误并抛出释放(以便服务器停止处理这个请求st,但不会完全停止响应)。

这让这样的代码,例如:

char const* func(ENUM x) 
{ 
switch(x) 
{ 
    case Option1: return "Option1"; 
    case Option2: return "Option2"; 
    case Option3: return "Option3"; 
} 
UNREACHABLE("func(ENUM)") 
} 
+2

第一种情况似乎是似是而非,因为如果该值未初始化,则具有UB,并且默认情况下不会对您有所帮助。 – Antimony 2014-05-06 02:15:56

+0

@Antimony:它实际上更加恶毒,在调试模式下,gcc会给你一个'0'(通常是enum的第一个成员),而在发布模式下,由于优化,任何事情都可能发生......这往往足够结果在一个垃圾值(和运气,警告!)。显然,我不会建议依靠它,因为根据定义UB是不可靠的。 – 2014-05-06 06:38:35