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

时间:2012-04-28 02:18:43

标签: c++ default switch-statement assert

假设我有一个枚举。

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。退出信息
我可以立即退出程序并出错。 这感觉就像是最好的主意,但我不确定这是不错的做法。我认为断言的优点是,当你准备好运送程序时,你可以将它们全部关掉。然后,所有断言代码将不再存在。


也许还有另一种我不知道的方式。我确实使用了一个编译器标志,警告有关未计入值的值,但我仍然想知道别人推荐的内容。

4 个答案:

答案 0 :(得分:9)

我喜欢用信息性的信息断言的想法。试试这个:

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

这总是返回false,但会提供您可以使用的消息。

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

答案 1 :(得分:4)

我喜欢这种特殊情况,即你打开一个枚举标签并处理所有情况,就是省略默认情况。这样,使用任何合理的编译器,如果有人向枚举而不是交换机添加新标签,您将收到关于交换机中未处理的标签的编译时警告。

答案 2 :(得分:0)

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

如果它会导致稍后不那么优雅的崩溃,你肯定想要在调用“带有无效枚举的函数:enumName”的解释时中断运行时或者给开发者通知他们没有更新这个切换语句,而不是让他们想知道以后是否会出现问题。

答案 3 :(得分:0)

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

答案很长: 解决根问题的最简单方法(即如何防止缺少条目的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