C++异常开销

Yip*_*Yay 32 c++ embedded arm exception overhead

为什么嵌入式平台开发人员不断尝试C++ exceptions从他们的用户中删除使用SDKs

例如,Bada SDK为异常使用建议以下解决方法,它看起来格外难看:

 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;
 }
Run Code Online (Sandbox Code Playgroud)

这种行为的原因是什么?

据我所知,ARM编译器完全支持C++ exceptions,实际上这不是问题.还有什么?是例外的使用和unwindings上的开销ARM平台真的有那么花很多时间做这样的解决方法?

也许其他我不知道的东西?

谢谢.

Dan*_*Dan 49

只差我2美分......

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

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

答案通常是以下几种组合:

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

此外 - 经常有一些模糊的不确定性/担心开销,但几乎总是它没有量化/未被发现,它只是被扔出去并采取了面值.我可以向您展示报告/文章,说明例外的开销是3%,10%-15%或~30% - 请您选择.人们倾向于引用转发自己观点的数字.几乎总是,文章已经过时,平台/工具集完全不同等等,正如罗迪所说,你必须在自己的平台上衡量自己.

我不一定在为这些职位辩护,我只是给你真实世界的反馈/解释我听过许多在嵌入式系统上使用C++的公司,因为你的问题是"为什么这么多嵌入式开发人员避免例外?"

  • 我的思想和经验也使我朝着这个方向前进,并补充说,添加到项目中的任何代码/二进制代码都会增加风险。如果从代码中添加的值不能弥补风险以及验证该代码所需的质量保证周期,则完全不添加它。嵌入式系统要比台式机系统更可靠,无论是否使用链接,任何或每一行代码或库blob都会增加风险。 (2认同)

jal*_*alf 19

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

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

  • 你能提供10-15%价值的参考吗?或者他们占用了大量的记忆? (11认同)
  • 我总是怀疑这些开销声明:开销相比什么?它是否使用15%以上的内存,在平均用例或实际触发异常的用例中运行速度是否慢了15%?还有什么其他错误捕捉技术比较?goto方法/错误号/ ...?因为他们都有他们的程序设计影响,这也会影响'开销'(这样一个通用术语......) (4认同)
  • @ edA-qa C++性能报告:http://www2.research.att.com/~bs/performanceTR.pdf,虽然它给出了不同的数字. (2认同)

Rod*_*ddy 7

这些天我认为这主要是FUD.

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

首先测量,优化第二.

但是,抛出异常通常比返回布尔标志要慢,因此仅抛出异常事件的异常.

在一种情况下,我看到RTL正在从符号表构建整个可打印的堆栈跟踪,只要抛出异常以进行潜在的调试使用.你可以想象,这不是一件好事.这是几年前的事情,当这个问题曝光后,调试库就被匆忙修复了.

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

编辑:

@jalf提出了一些好处,我上面的答案针对的是为什么许多嵌入式开发人员仍然贬低异常的相关问题.

但是,如果特定平台SDK的开发人员说" 不使用异常 ",那么您可能不得不接受它.也许他们的库或编译器中的异常实现存在特殊问题 - 或者他们担心回调中引发的异常会导致由于他们自己的代码中缺少异常安全而导致的问题.

  • "所以只为特殊事件抛出异常." +1 (4认同)

n. *_* m. 5

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

据我所知,这个想法几乎总是一种误解,但似乎有一些不可思议的原因,它有强大的支持者.

  • @DavidHammen您需要将异常与其他错误报告方案进行比较,而不是不带任何异常的异常。 (2认同)

Dav*_*men 5

在其他答案中支持一种相反的观点,即"邪恶是邪恶的".我正在制作这个社区维基,因为我知道这种相反的意见会受到抨击.

任何值得他们盐的实时程序员都知道这种用法goto.它是一种广泛使用且被广泛接受的处理错误的机制.许多硬实时编程环境不实现<setjmp.h>.例外是概念上受限制的版本setjmplongjmp.那么为什么在禁用基础机制时提供异常呢?

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

  • @大卫.Realtime是一个广泛的教会:我已经用PICs向上编译硬件实时系统,汇编程序,pascal,c,c ++已有30多年了.您可以使用对您的要求有意义的语言功能来简化工作.在许多情况下,RAII和模板是混合的一部分. (5认同)
  • 好吧,异常实际上只是一个gotos的抽象,沿途有自动RAII清理的优势:) (3认同)