“我们不使用C ++例外” - 有什么替代方案?让它崩溃?

时间:2010-08-16 01:45:06

标签: c++ exception

"We do not use C++ exceptions."

如果您不使用例外,那么在出现错误时会发生什么?你只是让程序崩溃了吗?

7 个答案:

答案 0 :(得分:27)

或者你可以进一步阅读:

  

在他们的脸上,使用的好处   例外超过成本,   特别是在新项目中。然而,   对于现有代码,引入   例外对所有人都有影响   依赖代码。如果例外可以   它超越了一个新项目   整合也会有问题   新项目进入现有   无异常代码。因为大多数   谷歌现有的C ++代码不是   准备好处理异常,它   采用比较困难   生成异常的新代码。

     

鉴于Google的现有代码是   不容忍异常,费用   使用例外有点大   而不是新项目的成本。   转换过程会很慢   并且容易出错。我们不相信   可用的替代品   例外,例如错误代码和   断言,介绍一个重要的   负担。

     

我们反对使用例外的建议是   不是基于哲学或哲学   道德理由,但实际的。   因为我们想用我们的   谷歌和谷歌的开源项目   如果那些,那很难做到   项目使用例外,我们需要   建议不要使用Google中的例外情况   开源项目也是如此。事情   如果我们有可能会有所不同   从头开始重新做一遍。

     

此规则有例外(没有   用于Windows代码的双关语。

答案 1 :(得分:24)

不,替代方法是做人们在C中做了多年的事情......你返回一个错误状态代码,指示函数是否成功,并且根据它可能失败的方式,你可能有一个或多个输出参数,在这些参数中你指明它失败的方式(或者你在错误状态代码中加入了失败的类型,这也是一个个案的事情)。

答案 2 :(得分:9)

除了返回码之外的其他例外的替代方案:

  • LISP风格的条件处理程序。
  • 软件信号和插槽,QT风格。
  • 硬件中断或信号处理程序,无需堆栈展开。它是堆栈展开,这是嵌入式设备上的异常问题。
  • longjmp / setjmp
  • 回调功能
  • 标志值,例如errorno(Unix),GetLastError(Windows),glGetError(OpenGL)等
  • 消息队列,如果程序是事件驱动的
  • 可变函子。处理程序对象作为输入输出参数,指针在出错时更改。
  • 具有错误解决协同例程的光纤或线程
  • asm __int 3或CPU-equivalent
  • 叠加说明或蹦床功能。

......还有更多。上面列出的许多都是嵌入式设备友好的。

答案 3 :(得分:7)

如果您没有按定义使用异常,则代码不会抛出异常,因此不需要捕获它。

它是“我们不使用C ++异常”,而不是“我们不会捕获C ++异常”。

答案 4 :(得分:6)

链接样式指南解释得很好:

  

在他们的脸上,使用的好处   例外超过成本,   特别是在新项目中。然而,   对于现有代码,引入   例外对所有人都有影响   依赖代码。如果例外可以   它超越了一个新项目   整合也会有问题   新项目进入现有   无异常代码。因为大多数   谷歌现有的C ++代码不是   准备好处理异常,它   采用比较困难   生成异常的新代码。

在C ++中相对容易创建健壮的代码而不使用异常或担心异常保证。使用返回码和断言,异常实际上仅限于程序员错误。

答案 5 :(得分:5)

如果你正在编写代码并达到一个问题,你已经确定了一个通常会引发异常的问题,但是希望遵守一些不会使用异常的规定,那么你必须找到另一个让客户端代码知道错误的方法。

正如许多现有的答案文档,您可以返回一个标记值(例如,真/假成功值,枚举)。这种做法在POSIX和libc指定的常见C函数中很常见,如fopen(),strstr()或printf()。

另一个重要选项是设置一些他们以后可以查询的内部状态。为什么你想要或需要做后者?因为某些函数(主要是C ++构造函数和运算符)通常不会为您提供返回错误代码的机会。例如,在:

  X x1(something), x2(whatever);
  fn(x1 + x2);

X::X(...)无法返回任何内容。可以调用X::operator+(假设转化运算符的结果未调用+),但fn()可能会期望const X&(或X&&与C ++ 11),operator+需要返回X,因此它在成功的情况下有效。您没有机会返回不同类型的错误代码。 class X可能需要设置一些内部状态,以便其他代码(可能fn(),也许是调用fn()之后的语句)进行测试以采取适当的操作。

所以,你最终得到的结果是:

X x1(something), x2(whatever);
assert(x1.is_valid() and x2.is_valid());
X x3 = x1 + x2;
assert(x3.is_valid());
fn(x3);

请注意,此错误处理约定很冗长,容易被客户端编码器忽略或忽略 - 这是创建异常的原因之一。大多数浮点硬件都使用了一个有趣的变体 - 某些操作,如除以0或低于/溢出,可以将寄存器设置为哨兵值,例如非数字“NaN”或+/-无穷大,然后是涉及参数的操作在这种状态下将状态传播到他们的结果。例如,x = 8 + y / 0; z = x + 2;也会将z设置为哨兵。这里的想法是您可以编写尽可能计算正确结果的代码,并在使用结果之前检查一次,以查看计算代码中任何位置的错误是否使该结果无效。它有时适用于数学代码,特别是当你没有根据变量的当前值做出分支决策时,但遗憾的是在许多情况下你要么不想要也不想让所有的用户都做出来。可能无效的目标代码超级防御地处理和传播错误状态。

在没有例外的情况下使用C ++严重损害了语言的可用性,可维护性,简洁性和优雅性。

作为完全禁止异常使用的替代方法,在某些环境中,您可以捕获API边界处的所有异常,然后以“C”样式返回错误代码或标记值。这允许内部更好的编码,但外部更好的互操作性。遗憾的是,有时使用异常是不切实际的,因为您的代码将在未提供异常处理机制的环境中执行...可能在内核,驱动程序或具有精简C ++样式编译器的嵌入式环境中执行。然而,这样的环境不是真正的C ++,因为它不符合标准。

答案 6 :(得分:3)

您使用错误代码返回版本的函数,并根据返回值执行操作。