【问题标题】:Error handling: distinguishing between 'fatal' errors and 'unexpected input' errors错误处理:区分“致命”错误和“意外输入”错误
【发布时间】:2011-10-02 19:16:43
【问题描述】:

我一直在开发一个读取 XML 文件的程序,如果 ifstream 无法打开该文件,它将抛出 std::ifstream::failure。只要设置了 std::ifstream::failbit 或设置了 std::ifstream::badbit 就会引发此异常,并且它们(至少在我看来)是需要处理异常的错误类型。

打开文件后,我使用 RapidXML 创建 DOM 对象,如果失败,它的 parse 函数会抛出 rapidxml::parse_error。在这种情况下,错误并不是真正致命的——它只是错误的输入。无论如何,我认为rapidxml在解析xml文件失败的时候抛出异常还是公平的,但即使我不这么认为,也无所谓,因为我没有太多的选择.我可以在 RapidXML 中关闭异常,但是我仍然必须手动处理这些异常情况,而且通过异常机制处理它们要容易得多。然而,这绝对是一个阴暗的领域。 rapidxml::parse 抛出异常的理由并不像 ifstream 那样明确。

最后一种情况是当我解析 DOM 并遇到意外或未预料到的节点时。显然,尽管有意外的输入,程序仍可以继续执行,但我不希望它这样做。可以想象,我可以在这里抛出一个异常,但我不确定这是否有意义。

所以,我想请教一个小建议:异常处理的最佳实践是什么?我尝试通过在构造函数中执行所有这些来在解析文件的类中使用 RAII 习惯用法。我使用 boost::shared_ptr 来实例化文件解析类,因此如果构造函数抛出,boost::shared_ptr 将在删除文件解析类后重新抛出 std::bad_alloc。

当 XML 文件不符合此类的预期时,我可以提出一个论据,我认为在出现意外输入时抛出异常是有意义的,但我真的很喜欢以确保我的思维过程是正确的。

【问题讨论】:

  • RAII 很棒,但我更喜欢微不足道的构造函数。如果您正在打开文件、连接套接字或在构造函数中执行任何其他容易发生故障的非分配逻辑,那么您应该抛出。
  • 琐碎的构造函数非常适合琐碎的事情,因为它们不容易出现您提到的异常情况。我唯一能想到的会掩盖您对琐碎构造函数的论点是内存不足异常……这在分配内存的构造函数中很有可能,但是我想当您说“琐碎构造函数”时,您可能并不意味着为类成员分配任何内存。
  • 我只是想指出,有一个构造函数可以创建许多对象、打开文件、解析 xml、检查输入的有效性等等,这对我来说也可能是一个巨大的做所有事情的功能违背了面向对象的原则。

标签: c++ boost exception-handling error-handling rapidxml


【解决方案1】:

您的设计对我来说很有意义:完全初始化或抛出异常。唯一想到的选择是:

  • 状态代码
  • 使用状态成员函数尽最大努力初始化以找出有效的部分

想到全有或全无方法的唯一缺点是处理“几乎正确”的输入。如果缺少属性,应用程序可能会更喜欢默认值。

【讨论】:

  • 感谢您的确认。输入的性质要求采用全有或全无的方法,因为如果文件格式的方式有任何错误,则此模块中的任何其他内容都没有任何意义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-05-29
  • 2019-05-16
  • 1970-01-01
  • 2011-04-19
  • 2018-08-17
  • 1970-01-01
  • 2010-12-26
相关资源
最近更新 更多