【问题标题】:Project level c++ exception handling strategy项目级c++异常处理策略
【发布时间】:2009-10-22 23:50:14
【问题描述】:

假设我在每个级别都有嵌套方法 a、b、c、d、e,我们在正常操作过程中返回错误,但 e 也可能引发异常(例如 STL 插入时内存不足)。例外情况很少见,实际平仓发生的快/慢不是问题。

在这种情况下,最合适的异常处理策略是什么?

  1. 将其放入最低级别并转换为正常错误条件。

优点:不需要编写异常安全代码,实现最简单,最容易测试,最容易理解,展开所需的最少编译时间信息。

缺点:看起来不太酷,增加了明显的 try/catch 咔嗒声 - 几乎在每个 insert 和 push_back 周围,直到围绕 STL 容器编写异常安全包装器的程度,有人认为 try 块存在运行时性能损失(也有观点认为根本没有惩罚)。

  1. 在顶部处理它。

优点:看起来很酷,没有杂音。

缺点:很难直观地验证中间的所有代码确实是异常安全的,测试所有异常展开路径都将是

  1. 将其作为应用程序的完全重新启动处理最顶部:清除所有未被异常处理破坏的内容并重新启动

优点:可预测,可以容忍异常安全代码中的小瑕疵,比崩溃要好得多。

缺点:太苛刻了

  1. 编写自定义分配器,允许在深入调用堆栈之前检查 a() 处的内存保留。

void a()
{
    ...
    x = b();
    ...
}

int b()
{
    y = c();

    ...

    return y + d();
}

int d()
{
    ...
    z = e();
    ...
}

【问题讨论】:

  • 我尝试格式化代码,但它不起作用,我不知道为什么..对不起。
  • 它与列表后的代码有关。我只是添加了一个分隔符,我不知道有什么其他的修复方法。
  • 也许你可以举一些例子说明你为什么认为:真的很难直观地验证中间的所有代码确实是异常安全的,以测试所有异常展开路径。例如,如果您使用范围对象,则无需担心它是如何展开的。
  • 谢谢大家的帮助。我下定决心编写异常安全代码而不处理内部任何异常:在我的目标系统上,由于自定义 STL 分配器允许为最坏的情况预留 STL 分配器,异常确实非常不可能发生,在通用系统上,这种可能性仍然很低,因为为了减少内存需求和仔细编码,因此在调用者的代码中处理异常似乎非常合适。顺便说一句,这个讨论的可怕之处在于,显然没有编译器验证异常安全。

标签: c++ exception-handling


【解决方案1】:

一般来说,我觉得系统最好始终使用单一的错误处理策略 - 每次在两者之间转换时,都会出现一些漏洞。大多数时候,我更喜欢任何合理支持它们的语言中的异常(即,不在 C 中 - setjmp/longjmp 是该死的)。鉴于您所描述的设计,您的系统中的大多数已经使用错误代码,将异常转换为 e 中的错误代码并假装您的系统中不存在异常似乎是有意义的。

另一方面,你确定只有e 可以抛出异常吗?在 C++ 中,从您通常不会想到的地方抛出异常是相当容易的 - 调用 new,几乎可以使用标准库,等等。

请注意,使用 RIAA 等技术的异常安全性在您拥有类似代码时也很有用

int* workspace[] = new int[500];
...
if(some_function() == ERROR)
  return SOME_FUNCTION_FAILED; // oops just leaked memory
...
delete[] workspace;

(或其他任何获取资源的东西)

RIAA 技术被认为是与异常相关的,但实际上只是它们在那里是完全必要的(因为你没有其他办法这样做),在错误代码处理技术中它们非常有用;虽然理论上您可以自己处理所有资源释放,但实际上您可以并且有时会忘记。让编译器来做(tm)

您真的需要尝试/捕获每个操作吗?为什么不将整个函数包装在 try/catch 中并返回错误。一方面,它更容易区分读取错误的std::vector 索引和抛出std::bad_alloc 的内存分配失败。

try/catch 的性能损失很大程度上取决于 ABI 和编译器。我相信在带有现代 GCC 的现代 ABI(例如 x86-64 Unix ABI)上,成本不为零但最小,但在其他编译器上它可能很明显。如果你真的想知道,你必须在你的特定编译器/平台上运行实验。

【讨论】:

【解决方案2】:

无论您在这里做出什么决定,我都鼓励您将异常安全的概念牢牢地敲入(或至少轻轻地敲击)其他开发人员的脑海中。以我的经验,编写异常安全代码的过程导致了设计更简洁的事务性代码。

作为一个好处,无论是否存在异常,这种编码风格都能正常工作,反之则不然。

【讨论】:

    【解决方案3】:

    我会根据几个因素做出决定。

    1) 您的代码库有多干净。如果您的代码库相对干净,则更容易验证您的代码是否是异常安全的,并且您可以在顶部捕获异常。但如果代码是乱七八糟的,则更容易捕获低级异常并依赖现有的错误处理。

    2) 你的团队有多好。假设您不是唯一编码的人,另一个需要处理的问题是您的所有团队成员是否都准备好编写异常安全代码。如果您的团队中有无法打破旧习惯的人,您应该将异常控制在较低水平,因为这样的程序员可能会随着时间的推移引入异常不安全的代码。

    【讨论】:

      猜你喜欢
      • 2011-01-23
      • 2016-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-16
      • 1970-01-01
      相关资源
      最近更新 更多