SF.
SF.

Reputation: 14059

Unhandled enum class value in switch() - Exception or Assert?

lvl is an enum class.

switch(lvl)
{
case LogLevel::Trace:
    return "Trace";
case LogLevel::Debug:
    return "Debug";
case LogLevel::Info:
    return "Info";
case LogLevel::Warning:
    return "Warning";
case LogLevel::Error:
    return "Error";
case LogLevel::Fatal:
    return "Fatal";
default:
    assert(0 && "Unhandled LogLevel in LevelToStr"); return "???";      // This one?
    throw std::invalid_argument( "Unhandled LogLevel in LevelToStr" );  // or this one?
}

The consensus is the default should be there, but the opinions in the related question are divided on what it should be doing. Crash the whole thing? Crash the current thread? Try to handle the exception gracefully?

The sides present some arguments in the comments but the discussion isn't quite conclusive.

Could someone present a comprehensive answer which one should be used, or in which conditions?

Upvotes: 2

Views: 2341

Answers (1)

Richard Hodges
Richard Hodges

Reputation: 69892

It completely depends on the requirements of your system.

I would actually argue that it's better not to use default: in this case. If you leave it out, you'll get a useful warning if you missed a case at compile time. If you compile with -Werror then your program will fail to compile until you've fixed the warning.

void handle_something(LogLevel lvl)
{
    switch(lvl)
    {
    case LogLevel::Trace:
        return "Trace";
    case LogLevel::Debug:
        return "Debug";
    case LogLevel::Info:
        return "Info";
    case LogLevel::Warning:
        return "Warning";
    case LogLevel::Error:
        return "Error";
    case LogLevel::Fatal:
        return "Fatal";
    // note: no default case - better not to suppress the warning
    }

    // handle the default case here

    // ok, so now we have a warning at compilation time if we miss one (good!)
    // next question: can the program possibly continue if this value is wrong?
   // if yes...
   return some_default_action();

   // ... do we want debug builds to stop here? Often yes since
   // ... this condition is symptomatic of a more serious problem
   // ... somewhere else

   std::assert(!"invalid log level");

   // ...if no, do we want to provide information as to why
   // ... which can be nested into an exception chain and presented
   // ... to someone for diagnosis?

   throw std::logic_error("invalid error level: " + std::to_string(static_cast<int>(lvl));

  // ... or are we in some mission-critical system which must abort and
  // ... restart the application when it encounters a logic error?

  store_error_in_syslog(fatal, "invalid log level");
  std::abort();
}

Upvotes: 2

Related Questions