使用throws来控制程序流?

时间:2016-11-29 11:11:28

标签: c++ throw program-flow

该计划通过class Menu与用户进行通信,因此main()如下所示:

int main() {
    try {
        Menu menu(/*...*/);
        while (true) {
            menu.printOptions();
            menu.chooseOption();
        }
    }
    catch (const char *error) { /*Resolve error.*/ }
    catch (int code) { /*Exit with code.*/ }
}

用于退出的当前class Menu选项是这样的:

void exit() {
    // Release memory.
    throw 0;
}

应该避免这样的构造,并且它们是否有一些不可预测的(或不希望的)副作用?

1 个答案:

答案 0 :(得分:1)

我会避免使用异常作为以这种方式控制流量的手段。相反,您可以将循环从while (true)更改为检查菜单类状态的内容,例如while (menu.isAlive())。退出只是将alive属性设置为false,这将结束while循环。

异常应该用于当前流无法恢复的情况,并且需要您将控制权返回给父流。话虽如此,没有什么可以阻止你以这种方式使用异常,但我个人认为错误处理的异常,从而隐藏跳转,但让它们用于常规流程已经够糟糕了控制,绝对是我认为会污染代码的东西,并使其不太可预测。

例外情况存在许多其他文章中关于反模式的问题:

  • 它们在很多方面类似于goto陈述,因为它们创造了"隐形"代码中的退出点,逻辑程序流在一些点上被破坏,这使得在常规调试器中逐步执行代码变得更加复杂。
  • 使用起来很贵。更多内容如下。
  • 使代码更难阅读。
  • 是设计问题的症状,应该解决。

我不反对所有情况下的例外情况,但我不认为所有处理"错误"情况应该用异常来完成,这取决于"错误"影响程序流程。例如,在错误(对不良措辞)真的是异常状态的情况下,例如当套接字死亡,或者您无法分配新内存或类似情况时,它非常有意义。在这些情况下,异常是有道理的,特别是因为异常很难被忽略。总结在我看来例外情况应该用于特殊情况。

还有其他答案可以解决您可能感兴趣的SO和其他Stack Exchange网站上的问题:
Are exceptions as control flow considered a serious antipattern? If so, Why?
Why not use exceptions as regular flow of control?

关于异常性能的说明,它是特定于实现的异常处理方式,它可能因编译器而异。但是,通常情况下,例外情况在采用非特殊路径时不会增加额外成本,但是在采用特殊路径时,有许多报告表明成本确实很高(https://stackoverflow.com/a/13836329/111143提到成本的10倍/ 20倍在特殊路径上定期if

由于异常的实现特定于编译器,因此很难给出任何一般性的答案。但是检查编译器生成的代码可能会显示使用异常时添加的内容。例如,在捕获异常时,您需要抛出异常的类型信息,这会增加抛出异常的额外成本。当你真正面对一个很少发生的异常状态时,这个额外的成本几乎没有什么区别。但是如果用来控制正常的程序流程就会变成一件昂贵的事情。

例如,请查看以下通过抛出整数退出的简单代码示例:https://godbolt.org/g/pssysL添加全局变量以防止编译器优化返回值。将此与使用返回值的简单示例进行比较:https://godbolt.org/g/jMZhT2异常在采用非异常路径时具有相同的成本,但是采用异常路径会变得更加昂贵。如果异常用于真正特殊的情况,但在用于特殊路径"的情况下,这可以很好。受到更频繁的打击,成本开始成为一个因素。