C ++异常开销

C++ exception overhead

为什么嵌入式平台开发人员会继续尝试从他们的SDKs中删除C++ exceptions的使用?

例如,Bada SDK建议对异常用法进行以下变通,这看起来异常丑陋:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 result
 MyApp::InitTimer()
 {
    result r = E_SUCCESS;

    _pTimer = new Timer;

    r = _pTimer->Construct(*this);
    if (IsFailed(r))
    {
        goto CATCH;
    }

    _pTimer->Start(1000);
    if (IsFailed(r))
    {
        goto CATCH;
    }

    return r;
 CATCH:
     return r;
 }

这种行为的原因是什么?

据我所知,ARM编译器完全支持C++ exceptions,这实际上不是问题。还有什么?ARM平台上的异常使用和解除开销是否真的如此之大,以至于花费大量时间来解决这些问题?

也许还有什么我不知道的?

谢谢您。


只是我的2美分…

我专门咨询嵌入式系统,其中大多数都是硬实时和/或安全/生命关键的。它们中的大多数运行在256K或更低的闪存/ROM中——换句话说,它们不是"PC式"的VME总线系统,具有1GB+的RAM/闪存和1GHz+的CPU。它们是深度嵌入的,有点资源限制的系统。

我想说,至少75%的使用C++的产品在编译器中禁用异常(即,用禁用异常的编译器开关编译的代码)。我总是问为什么。信不信由你,最常见的答案不是运行时或内存开销/成本。

答案通常是混合的:

  • "我们不相信我们知道如何编写异常安全代码"。对他们来说,检查返回值更熟悉、更不复杂、更安全。
  • "假设您只在异常情况下抛出异常,则在这些情况下,我们无论如何都会重新启动[通过它们自己的关键错误处理程序例程]。"
  • 遗留代码问题(正如JALF所提到的)-他们使用的代码始于许多年前,当时他们的编译器不支持异常,或者没有正确或有效地实现异常。

而且-经常会有一些关于开销的模糊的不确定性/恐惧,但几乎总是没有量化/未归档的,只是有点像从表面上看的那样。我可以向您展示声明异常开销为3%、10%-15%或~30%的报告/文章。人们倾向于引用这个数字来表达他们自己的观点。几乎总是,这篇文章过时了,平台/工具集完全不同,等等。正如Roddy所说,您必须在平台上衡量自己。

我不一定要捍卫这些立场,我只是给你真实的反馈/解释,我听到许多公司的工作与C++在嵌入式系统上,因为你的问题是"为什么这么多的嵌入式开发人员避免异常?"


我可以想到几个可能的原因:

  • 旧版本的编译器不支持异常,因此编写了许多代码(并建立了约定),其中不使用异常
  • 异常确实有一定的成本,它可能高达总执行时间的10-15%(它们也可以实现为几乎不花时间,但使用相当多的内存,这在嵌入式系统上也可能不是很理想的)
  • 嵌入式程序员往往对代码的大小、性能和(尤其是)代码的复杂性有点偏执。他们经常担心"高级"功能可能无法与编译器一起正常工作(而且他们也经常是正确的)


我想这几天大部分都是软糖。

在创建具有构造函数/析构函数的对象的块的入口和出口处,异常确实有很小的开销,但在大多数情况下,这实际上不应该是一罐bean。

先量后优。

但是,引发异常通常比返回布尔标志慢,因此只针对异常事件引发异常。

在一个案例中,我看到每当抛出异常以供潜在的调试使用时,RTL都在从符号表构建整个可打印的堆栈跟踪。你可以想象,这不是件好事。这是几年前的事了,当这件事曝光时,调试库被匆忙修复了。

但是,在IMO中,正确使用异常可以获得的可靠性远远超过轻微的性能损失。使用它们,但要小心。

编辑:

@JALF提出了一些很好的观点,我上面的回答是针对一个相关的问题,即为什么许多嵌入式开发人员通常仍然轻视异常。

但是,如果一个特定的平台SDK的开发人员说"不要使用异常",那么您可能必须这样做。可能他们的库或编译器中的异常实现存在特定的问题,或者他们担心回调中抛出的异常,这会导致由于他们自己的代码中缺乏异常安全性而产生问题。


与"哥特人是邪恶的"相反的观点在其他答案中得到了支持。我创建这个社区wiki是因为我知道这个相反的观点会被激怒。

任何值得一试的实时程序员都知道goto的这种用法。它是一种广泛使用和广泛接受的错误处理机制。许多硬实时编程环境不实现。在概念上,例外只是setjmplongjmp的受限版本。那么,当底层机制被禁止时,为什么要提供异常呢?

如果始终可以保证在本地处理所有抛出的异常,则环境可能允许异常。问题是,为什么要这样做?唯一的理由是哥特人总是邪恶的。嗯,他们并不总是邪恶的。


这种对待异常的态度与性能或编译器支持无关,而一切都与异常增加代码复杂性的想法有关。

据我所知,这个想法几乎总是一种误解,但由于一些不可想象的原因,它似乎有强有力的支持者。


现代C++编译器可以将异常的运行时使用减少到开销的3%。尽管如此,如果极端的程序员发现它很昂贵,那么他们就会诉诸于这种卑鄙的把戏。

请参见bjarne strourstrup的页面,了解为什么使用异常?