除了()之外,C ++异常是否应提供其他详细信息

时间:2012-11-12 10:38:37

标签: c++ exception

除了what()之外,我的异常类是否应该在公共字段中提供详细信息?

考虑例如boost::property_tree::ptree_bad_path可能会给出一条消息:

"No such node (mynode.value1)"

访问路径("mynode.value1")的唯一方法是解析字符串。是否存在反对添加其他公共字段以携带此类信息的论点,即:

class ptree_bad_path : public ptree_error {
public:
  const std::string path; // <- additional detail by public field
....

这种方法有缺点吗?

4 个答案:

答案 0 :(得分:2)

您的异常类应包含处理错误所需的所有信息。这通常意味着用错误和任何必要的上下文标记它。最好将路径存储在异常类中。

  

这种方法有缺点吗?

尽量避免让成员自己抛出,因为他们会调用std :: terminate。

答案 1 :(得分:2)

理论上,如果您同时有两个未处理的异常,则可能会遇到程序terminate。然而,这是一种相当罕见的情况。

  • 在准备例外期间投掷:罚款(虽然你不会得到你预期的例外)
  • 在异常副本期间投掷(通常省略,可避免):崩溃
  • 放松期间投掷:崩溃
  • 在处理异常(catch)期间抛出:很好(毕竟,重新抛出一个不同的异常很常见)

所以,这里可避免的风险是你的异常的拷贝构造函数可能会抛出。通过将状态移到异常中包含的shared_ptr来避开问题是微不足道的。它使副本有点“特殊”(因为它们与原始状态共享它们的状态)但是如果它被正确记录它不应该引起任何悲伤。

堆栈展开期间风险更大。但是只有在析构函数抛出时才会发生。

就个人而言,我使用的例外包含:

  • 一个错误代码(用于正确显示/编码的API,所有错误消息都映射到一个代码,它真的有中文/韩文/日文帮助)
  • 一条日志消息,包含一些细节(导致问题的项目的ID /名称,翻译另一个异常时的原始错误,无论有什么帮助!)
  • 抛出异常的函数/ file /行
  • 抛出异常的时间
  • 附加说明(在堆栈展开期间“动态”附加)
  • 完整的回溯(使用Linux特定功能)

这里唯一有争议的一点是动态位,因为它可能会有效崩溃。另一方面,我在服务器上工作,因此很容易(并且紧急)修复了崩溃,并且在过去的5年里我非常小心,不会导致崩溃(这种方式;))。

请注意,此方案显然仅在稀疏地使用异常时才可用。如果您经常为每个任务抛出十几个异常,那么性能可能是不可接受的。另一方面,主要编制者使用的零成本模型已经严厉地惩罚了特殊的路径,所以......

答案 2 :(得分:1)

这只是我的意见,但如果您要抛出异常,您可能需要确保它有足够的信息让您知道(a)导致异常的原因,以及(b)抛出异常的位置

您可能(希望)不会向最终用户显示异常,因此记录异常会成为纯粹启用/提高可支持性的东西。因此,从发展的角度来看,您基本上希望能够尽可能地了解所发生的事情。

当然,你在这里走一条细铁线是正确的。您不希望在异常处理中使用这样复杂的代码,因为它冒着抛出自己的异常的风险!

答案 3 :(得分:0)

您的例外情况可能会带有捕捉者准备好(并愿意)使用的信息。如果您的特定应用程序可以使用此附加信息,您可以放心地编写自己的异常类。在任何情况下,所有异常类都应继承自std::exception,以确保不期望自定义异常的catch子句能够正常工作。

另一个问题是在第三方客户端使用的库上公开这些类。在这种情况下,您应该仔细考虑这些额外信息的好处是否超过了额外界面引入的麻烦,甚至可能根本不使用它。

编辑:作为Pubby says,您的异常类不应抛出以避免对std::terminate()的不受欢迎的调用。通常,不应抛出与异常相关的代码,这包括任何类的析构函数。