Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using default in a switch statement when switching over an enum

People also ask

Can you use a switch statement around an enum?

An Enum keyword can be used with if statement, switch statement, iteration, etc. enum constants are public, static, and final by default. enum constants are accessed using dot syntax. An enum class can have attributes and methods, in addition to constants.

What does the default clause do when using a switch statement?

The default statement is executed if no case constant-expression value is equal to the value of expression . If there's no default statement, and no case match is found, none of the statements in the switch body get executed. There can be at most one default statement.

Should a switch statement always have a default?

No it is not necessary of default case in a switch statement and there is no rule of keeping default case at the end of all cases it can be placed at the starting andd middle of all other cases.

Can an enum have a default value?

The default value for an enum is zero. If an enum does not define an item with a value of zero, its default value will be zero.


I throw an exception. As sure as eggs are eggs, someone will pass an integer with a bad value rather than an enum value into your switch, and it's best to fail noisily but give the program the possibility of fielding the error, which assert() does not.


I would put an assert.

Special make_special( Enum e )
{
    switch( e )
    {
        case Enum_One:
            return Special( /*stuff one*/ );

        case Enum_Two:
            return Special( /*stuff two*/ );

        default:
            assert(0 && "Unhandled special enum constant!");
    }
}

Not handling an enumeration value, while the intention is to cover all cases, is an error in the code that needs to be fixed. The error can't be resolved from nor handled "gracefully", and should be fixed right away (so i would not throw). For having the compiler be quiet about "returning no value" warnings, call abort, like so

#ifndef NDEBUG
#define unreachable(MSG) \
  (assert(0 && MSG), abort())
#else
#define unreachable(MSG) \
  (std::fprintf(stderr, "UNREACHABLE executed at %s:%d\n", \
                __FILE__, __LINE__), abort())
#endif 

Special make_special( Enum e )
{
    switch( e )
    {
        case Enum_One:
            return Special( /*stuff one*/ );

        case Enum_Two:
            return Special( /*stuff two*/ );

        default:
            unreachable("Unhandled special enum constant!");
    }
}

No warning by the compiler anymore about a return without value, because it knows abort never returns. We immediately terminate the failing program, which is the only reasonable reaction, in my opinion (there is no sense in trying to continue to run a program that caused undefined behavior).


First of all, I would always have a default in a switch statement. Even if there are no idiots around to cast integers to enums, there's always the possibility of memory corruption that the default can help to catch. For what it's worth, the MISRA rules make the presence of a default a requirement.

Regarding what you do, that depends on the situation. If an exception can be handled in a good way, handle it. If it's a state variable in a non-critical part of code, consider silently resetting the state variable to the initial state and carrying on (possibly logging the error for future reference). If it is going to cause the entire program to crash in a really messy way, try to fall over gracefully or something. In short, it all depends on what you're switching on and how bad an incorrect value would be.


As an additional remark (in addition to other responses) I'd like to note that even in C++ language with its relatively strict type-safety restrictions (at least compared to C), it is possible to generate a value of enum type that in general case might not match any of the enumerators, without using any "hacks".

If you have a enum type E, you can legally do this

E e = E();

which will initialize e with zero value. This is perfectly legal in C++, even if the declaration of E does not include a enumeration constant that stands for 0.

In other words, for any enum type E, the expression E() is well-formed and generates zero value of type E, regardless of how E is defined.

Note, that this loophole allows one to create a potentially "unexpected" enum value without using any "hacks", like a cast of an int value to enum type you mentioned in your question.


Your items are good. But I'd remove 'throw catchable exception'.

Additional:

  • Make warnings to be treated as errors.
  • Add logging for default cases.

As a further option: Avoid switching over enums.