异常层次结构与错误枚举

时间:2009-01-13 07:36:55

标签: c++ exception

我在某处读到(现在找不到)大型异常层次结构是浪费时间。这个陈述的理由在当时似乎很合理,这个想法一直困扰着我。

在我自己的代码中,当我有一个可以有一系列错误条件的代码库时,我使用一个枚举成员的异常来区分它们。

如果出现我需要抓住其中一个错误的情况,我会抓住它,检查枚举并重新抛出是否不符合我的预期。理想情况下,这应该是罕见的。

我再次处理异常,我有一个反思的时刻,我质疑我的异常习惯。我很好奇其他人做了什么以及为什么?

数据成员的层次结构或一个例外。

顺便说一句,我假设您同意异常与错误代码的概念。我不想打开那种虫子。

8 个答案:

答案 0 :(得分:12)

简单的经验法则:

  • 如果您在检查异常后最终重新抛出异常,那么您需要一个更精细的异常层次结构(除了极少数情况下,检查需要相当多的逻辑)。
  • 如果你有从未被捕获的异常类(只有它们的超类型),那么你需要一个不那么精细的异常层次结构。

答案 1 :(得分:11)

我认为只有一个嵌入枚举的异常类型不是最理想的:

  1. 你被迫比必要更频繁地捕获异常(并且一旦你确定你无法处理它就重新抛出它)。
  2. 枚举本身就变成了一个变化的热点(所有程序员都需要定期修改它)
  3. 枚举不是分层的,例如,您无法轻松处理一个处理程序的所有IO错误
  4. 有时您还希望为呼叫者提供除错误消息文本之外的其他信息,例如:未找到的文件的路径或从SQL Server收到的错误号。将所有可能的错误场景中的其他信息放入同一个异常中会使处理变得更加麻烦。
  5. 要回答你的问题,我正在使用异常层次结构。它比它的深度要广泛得多。

答案 2 :(得分:7)

你不应该对此有教条。使用最适合手头问题的东西。我的经验法则如下:

  • 仅在需要不同 行为 的异常时才创建新的异常类。
  • 相反,当您只想要包含异常的额外信息时,将内容(枚举,错误代码等)添加到异常类
  • 除非您确实需要,否则不要创建新类。记住,YAGNI ......

答案 3 :(得分:4)

我认为你正处于两个世界中最糟糕的世界。大型异常层次结构是无用的,因为已知客户端是惰性的,并且最终仅检查顶层节点(可能仅针对层次结构根)。你的枚举系统没有解决这个问题,并且使得一个更加麻烦的异常捕获系统。

如果你真的知道需要很多不同的例外,并且捕手真的想要不同的例外(知道,而不是模糊地思考),继续大的层次结构并忘记枚举。否则,坚持使用小的异常层次结构,并且只提供对捕获者来说真正有用的异常类。

答案 4 :(得分:3)

根据我的经验,太多的异常类只会让人感到困惑,特别是它们只用于一种非常特殊的问题。我已经看到一个系统,其中每个错误条件都有它自己的异常,但只有在catch块中检查了超类。子类完全是浪费时间。

另一方面,必须检查枚举并重新抛出异常会使代码不那么直观,因为您无法识别catch之后直接抛出的异常。也许只是一个小缺点,但如果经常使用它会对可读性产生影响。当在需要非常快的代码中使用时,它也可能造成性能问题。

我不会使用枚举解决方案,而是使用一些具有足够广泛频谱的异常类型。就像DatabaseException而不是像TableNotFoundException,ColumnNotFoundexception等几个例外一样。根据我的经验,这对大多数开发人员来说效果最好。您始终可以添加一个字段,其中包含您向用户显示的一些错误代码,以便更轻松地在用户和支持之间进行通信。

答案 5 :(得分:2)

通过使用一个异常类型和枚举子类型替换它们,您无法解决太多异常类的问题。事实上,你只会让事情变得更糟!

示例:假设您有Exception类型Ex1..Ex99,例如E14..E18是E1等的孩子。您现在决定将它们替换为Ex和子类型ST1..ST99之外的一个例外。你有什么解决的?没什么 - 人们仍然需要处理所有可能性。你做得更糟糕了什么?您不能忽略ST14-ST18并将它们视为ST1的出现。你现在必须处理所有99种可能性,因为你的枚举子类型没有自然,灵活的层次结构。

答案 6 :(得分:1)

不要将错误与例外混为一谈 错误发生,尽可能地解决问题 例外是罕见的,如果没有更多的上下文信息,通常无法解决。

如果出现问题并且可以在本地纠正,那么您应该使用错误代码并在那里处理它。

应该使用异常将问题在调用堆栈中传播到具有足够信息来解决问题的上下文。

这样说:枚举不是可行的方法,因为它们绕过了编译器将自动生成的整个try catch机制。

答案 7 :(得分:0)

我喜欢为不同的错误分类设置少量例外,例如致命/非致命条件或应用程序的特定层或模块。然后,异常的thrower应提供代码作为异常的有效负载。应用程序的表示层可以查找与代码对应的本地化人类可读错误消息。

总之,异常类型对开发人员很有用,对应于错误代码的消息对用户很有用。