Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compiler warning when switching on an enum

enum ENUM(Option1,Option2,Option3);

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

This compiles and works but gives a compiler warning that not all control paths return. However isn't the point that if you use enums properly, this isn't the case? If another ENUM val is added, I want compilation to fail but as long as all cases are covered I want it to compile warning-free.

Is this the compiler protecting against bad casted values, is it just part of C++ and needs to be lived with?

like image 569
Mr. Boy Avatar asked May 09 '11 10:05

Mr. Boy


1 Answers

In C++, enums are not safe. You cannot expect an enum value to be one of the values defined in the enum declaration:

  • it could be uninitialized (thus garbage)
  • you could have an improper static_cast from a int

Therefore, the compiler cannot expect the switch to return, even if you cover all elements of your enum. However, it is truly an error condition, functionally speaking.

There are two ways to react:

  • add a default case to your enum
  • add a statement after the switch

In order to choose wisely, remember that the compiler may (if you ask it) trigger a warning whenever a switch does not cover all the cases of an enum, at the condition that there is no default statement. Smart compilers (ie Clang) allow to map warnings to errors individually, which greatly help catching those bugs.

Therefore, you have a decision to take:

  • if you want to be notified whenever you forget to change this method after updating the enum, then do not use default
  • if you want to be able to update the enum and ignore this switch, then use the default

Finally, you have to decide how to react, noting that using a runtime error is inconsistent with using a default statement (it's best to catch errors at compile-time whenever possible):

  • ignore the error and return some predefined value
  • throw an exception (with the enum value, please)
  • assert (and thus crash hard in debug, to get a memory dump, and do something else in release, like nothing, or throwing an exception)

My personal fav is a UNREACHABLE(Text_) macro, which provokes a memory dump in Debug (so that I get a full trace) and log an error and throw in Release (so that the server stops processing this request, but does not stop responding altogether).

This gives code like such:

char const* func(ENUM x)
{
 switch(x)
 {
  case Option1: return "Option1";
  case Option2: return "Option2";
  case Option3: return "Option3";
 }
 UNREACHABLE("func(ENUM)")
}
like image 106
Matthieu M. Avatar answered Sep 28 '22 18:09

Matthieu M.