在交换机的默认标签中放置什么

What to put in a default label of a switch?

本文关键字:什么 标签 交换机 默认      更新时间:2023-10-16

假设我有一个枚举。

enum class ShapeName : char {TRIANGLE,CIRCLE,SQUARE};

后来我有这样的函数:

void Function (ShapeName const shape){
    switch (shape){
        case ShapeName::TRIANGLE:
            DoSomething1();
            break;
        case ShapeName::CIRCLE:
            DoSomething2();
            break;
        case ShapeName::SQUARE: 
            DoSomething3();
            break;
        default:
            //THIS CODE BLOCK SHOULD NEVER BE EXECUTED!
    }
    return;
}

虽然默认标签永远不应该被执行,但我想考虑一下如果程序员向"ShapeName"添加另一个值并且没有在开关中考虑它可能出现的潜在错误。
你会建议我做什么?

1. 断言
我可以使用断言,但我在断言什么?

assert(false); //?

2. 例外情况
我可以抛出一个例外,但我认为这不是很好的做法。 我的印象是,异常是针对由于某些环境而无法预测的运行时事件。

3. 退出
我可以立即退出程序并出现错误。这感觉是最好的主意,但我不确定这是否是好的做法。 我认为断言的优点是,当您准备好发布程序时,您可以将断言全部关闭。然后,所有这些断言代码将不再存在。


也许还有另一种我不知道的方式。 我确实使用了一个编译器标志来警告未解释的值,但我仍然想知道其他人的建议。

我喜欢

用信息丰富的消息断言的想法。试试这个:

assert (!"The default case of so-so switch was reached.");

这始终返回 false,但提供您可以使用的消息。

编辑:
我找到了我从记忆中拉出这个概念的来源;它在下面的书中:
C++编码标准 - 101 规则和准则

对于这种特定情况,即您打开枚举标签并处理所有情况,我的偏好是省略默认值。 这样,对于任何合理的编译器,如果有人将新标记添加到枚举而不是交换机,您将收到有关标记未在交换机中处理的编译时警告。

我想对我来说,这在某种程度上取决于DoSomething#方法的作用。

如果以后会导致不太优雅的崩溃,您肯定希望在调用运行时中断运行时,并解释"使用无效的枚举调用的函数:enumName"或向开发人员发出通知他们没有更新此 switch 语句的内容,而不是让他们想知道以后是否失败。

简短回答:使用多态性来消除问题。

长答案:解决根本问题(即如何防止缺少条目的switch语句?(的最简单方法是避免使用switch语句,如果有可能忘记条目。 switch 语句在本地上下文中很有用,但如果它们表示的逻辑在多个位置重复,则可能会忘记更新一个语句,并且您正在为运行时错误设置自己。

class Shape
{
    // functionality MUST be added for new shape types
    // or a compile error will occur
    virtual void DoSomething() const = 0;
};
void Function (Shape const & shape){
    return shape.DoSomething();
}

switch 语句在创建站点可能仍然有用:

enum class ShapeName : char {TRIANGLE,CIRCLE,SQUARE};
unique_ptr< Shape > MakeShape (ShapeName const shape){
    switch (shape){
        case ShapeName::TRIANGLE:
            return unique_ptr< Shape >( new Triangle() );
        case ShapeName::CIRCLE:
            return unique_ptr< Shape >( new Circle() );
        case ShapeName::SQUARE: 
            return unique_ptr< Shape >( new Square() );
     }
     throw std::runtime_error();
     // or whichever option you prefer from the other answers
}

但这是逻辑存在的唯一地方。 甚至这也可以通过静态多态性进行改进:

enum class ShapeName : char {TRIANGLE,CIRCLE,SQUARE,ELLIPSE};
template< ShapeName shape >
unique_ptr< Shape > MakeShape();
template<>
unique_ptr< Shape > MakeShape< ShapeName::TRIANGLE >()
{
    return unique_ptr< Shape >( new Triangle() );
}
template<>
unique_ptr< Shape > MakeShape< ShapeName::CIRCLE >()
{
    return unique_ptr< Shape >( new Circle() );
}
template<>
unique_ptr< Shape > MakeShape< ShapeName::SQUARE >()
{
    return unique_ptr< Shape >( new Square() );
}
int main()
{
    MakeShape< ShapeName::TRIANGLE >(); // okay
    MakeShape< ShapeName::ELLIPSE >(); // compile error
}

参见 Martin Folwer 了解更多信息。