Compiler warning when listing is enabled

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 the compiler a warning that not all control paths are returned. However, it doesnโ€™t matter if you use enums correctly, isnโ€™t it? If another ENUM-shaft is added, I want the compilation to fail, but while all cases are closed, I want it to compile without warning.

Is this a compiler that protects against invalid values, is it just part of C ++ and need to live with?

+4
source share
3 answers

What happens if, for some reason, x is neither Option1 , nor Option2 , nor Option3 ?

Of course, it can be argued that this will never happen, but since the method must return something, you have two options:

  • add return string(""); In the end.

  • add default to switch , which returns string("") .

As CodeGray points out, the second option is probably the best style. You can also return something other than an empty string.

+3
source

From the point of view of compilers, an enum type is an integer, so it is still possible that the value of x is one of the other cases.

Usually I added the default: label, which triggers an internal error.

Hint. If you end the call with an intern error in an infinite loop, you do not need to invent a dummy return value. For instance:

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

In C ++, enums are unsafe. You cannot expect the enumeration value to be one of the values โ€‹โ€‹defined in the enumeration declaration:

  • it can be uninitialized (thus garbage)
  • you may have the wrong static_cast from int

Therefore, the compiler cannot wait for the switch to return, even if you cover all the elements of your enumeration. However, this is indeed a condition of error, functionally speaking.

There are two ways of reaction:

  • add default to your enum
  • add instructions after switching

To choose the right one, remember that the compiler can (if you ask it) raise a warning whenever the switch does not cover all cases of enum provided that there is no default expression. Intelligent compilers (for example, Clang) allow you to correlate warnings with errors individually, which helps to catch these errors.

Therefore, you have a decision to accept:

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

Finally, you need to decide how to respond, noting that using a runtime error is incompatible with the default instruction (it is best to catch errors at compile time when possible):

  • ignore the error and return some predefined value
  • throw an exception (indicating the value of the listing, please)
  • assert (and thus crashing in debugging, getting a memory dump and doing something else in the release, like nothing or an exception)

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

This gives the following code:

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

All Articles