如何实施例外情况?

几乎每个人都使用它们,但是包括我在内的许多人都认为他们只是工作而已。

我正在寻找高品质的材料。 我使用的语言是:Java,C,C#,Python,C ++,所以这些是我最感兴趣的。

现在,C ++可能是一个很好的开始,因为你可以用这种语言来抛出任何东西。

另外,C接近assembly。 如何使用纯C构造模拟exception并且不进行汇编?

最后,我听到有传闻说,由于速度方面的考虑,Google员工不会在某些项目中使用例外情况。 这只是一个谣言? 如果没有他们,任何事情都可以实现

谢谢。

例外情况只是高级非本地stream量控制结构的一般情况的一个具体例子。 其他的例子是:

  • 通知 (exception的泛化,最初来自一些旧的Lisp对象系统,现在在CommonLisp和Ioke中实现)
  • 延续 (更高层次,更高阶语言的GOTO结构化forms),
  • 协程 (一种子程序的泛化,在Lua中尤其受欢迎),
  • Python的生成器 (基本上是一个限制forms的协程),
  • 纤维 (合作轻质线),当然也已经提到
  • GOTO

(我相信还有很多人错过了。)

这些构造的一个有趣的特性是,它们在performance力上大致相当:如果你有一个 ,你可以很容易地构build所有其他的。

那么,如何最好地实现exception取决于你有什么其他的结构:

  • 每个CPU都有GOTO ,因此如果必须的话,你总是可以回退到那个地步。
  • C有setjmp / longjmp ,它们基本上是MacGyver的延续(用胶带和牙签build造的,不是真正的东西,但是如果你没有更好的东西,至less可以让你摆脱眼前的麻烦)。
  • JVM和CLI有自己的例外,这意味着如果你的语言的exception语义匹配Java的/ C#的,你是自由的(但如果没有,那么你是拧)。
  • 鹦鹉虚拟机作为例外和延续。
  • Windows有自己的exception处理框架,这些语言实现者可以使用它来构build自己的exception。

一个非常有趣的用例,例外的使用和例外的实现是Microsoft Live Lab的Volta项目。 (现在已经失效)Volta的目标是通过button为Web应用程序提供架构重构。 因此,只需在.NET代码中添加一些[Browser][DB]属性,就可以将单层Web应用程序转变为两层或三层应用程序,然后代码将自动运行在客户端或D B。 为了做到这一点,显然.NET代码必须被翻译成JavaScript源代码。

现在,您可以使用JavaScript编写整个虚拟机,并且可以不加修改地运行字节码。 (基本上,将CLR从C ++移植到JavaScript)。实际上有些项目(例如HotRuby VM),但是这样做效率低下,并且与其他JavaScript代码不能很好地互操作。

所以,他们写了一个将CIL字节码编译成JavaScript源代码的编译器。 然而,JavaScript缺乏.NET所具有的某些function(生成器,线程,这两个exception模型也不是100%兼容的),更重要的是它缺less编译器作者喜欢的某些function( GOTO或continuation),可以使用执行上述缺失的function。

但是,JavaScript 确实有例外。 所以,他们使用JavaScript Exceptions来实现Volta Continuations ,然后他们使用Volta Continuations来实现.NET Exceptions.NET Generators ,甚至.NET Managed Threads (!!!)。

所以,要回答你原来的问题:

如何实施例外情况?

有例外,讽刺! 至less在这个非常具体的情况下,无论如何。

另外一个很好的例子是Go邮件列表中的一些exception提议,它们使用Goroutine实现exception(像并发协程和CSP过程的混合)。 另一个例子是Haskell,它使用Monad,懒惰评估,尾部调用优化和更高阶的函数来实现exception。 一些现代CPU还支持exception的基本构build块(例如专为Azul系统Java计算加速器devise的Vega-3 CPU)。

以下是实现C ++exception的常用方法:
http://www.codesourcery.com/public/cxx-abi/abi-eh.html

它适用于Itanium体系结构,但此处介绍的实现也适用于其他体系结构。 请注意,这是一个很长的文档,因为C ++exception很复杂。

以下是关于LLVM如何实现exception的一个很好的描述:
http://llvm.org/docs/ExceptionHandling.html

由于LLVM旨在成为许多运行时的通用中间表示,所描述的机制可以应用于多种语言。

在他的着作“ C接口与实现:创build可重用软件的技巧”一文中 ,Hanson提供了使用一组macros和setjmp/longjmp在纯C中很好地实现exception的方法。 他提供TRY / RAISE / EXCEPT / FINALLYmacros,它们可以模拟C ++exception所做的所有事情。

代码可以在这里阅读(看看except.h / except.c)。

PS是关于Google的问题。 他们的员工实际上被允许在新的代码中使用例外,旧代码中的禁令的官方原因是因为它已经是这样写的,混合样式是没有意义的。

就我个人而言,我也认为C ++没有例外是不是最好的主意。

C / C ++编译器使用底层的操作系统工具来进行exception处理。 .Net或Java等框架在VM中也依赖于OS设施。 例如在Windows中,真正的繁重工作是由结构化exception处理基础设施SEH完成的。 您应该完全阅读旧的参考文章: 关于Win32™结构化exception处理深度的崩溃课程 。

至于不使用exception的成本,它们是昂贵的,但比较什么? 与返回错误代码相比? 在考虑了代码的正确性和代码质量之后,例外情况总是会在商业应用程序中获胜。 less数非常关键的操作系统级别的function,例外总是更好。

最后但并非最不重要的是使用exception进行stream量控制的反模式。 例外情况应该是例外的,滥用stream量控制例外的代码将在性能上付出代价。

有关实施例外情况的最佳论文(内幕)是Barbara Liskov和Alan Snyder 在CLU的例外处理 。 每当我开始一个新的编译器时,我都提到了它。

对于C语言中使用setjmplongjmp更高层次的实现,我推荐Dave Hanson的C接口和实现 (比如Eli Bendersky)。

exception实现需要处理的关键是如何在抛出exception后返回exception处理程序。 由于C ++中的try语句之后,您可能已经创build了任意数量的嵌套函数调用,所以必须展开调用堆栈来search处理程序。 然而,为了执行这个操作,这必须招致维护足够信息的代码量成本 (通常意味着可能需要exception的调用的数据表)。 这也意味着dynamic代码执行path将比从函数调用(这在大多数平台上相当便宜的操作)简单地返回更长 。 根据实施情况,可能还有其他成本。

相对成本会根据使用的语言而有所不同。 使用的是更高级别的语言,代码大小成本的可能性就越小,无论是否使用exception,信息都可以保留。

embedded式固件通常避免使用exception(通常是C ++)的应用程序。 在典型的小型裸机或RTOS平台中,您可能有1MB的代码空间,或64K甚至更小。 有些平台如此之小,即使C也不实用。 在这种环境下,由于上述成本,尺寸的影响是相关的。 它也影响标准库本身。 embedded式工具链供应商经常会产生一个没有例外能力的库,这对代码大小有很大的影响。 高度优化的编译器也可能会分析调用图并优化掉放开操作所需的调用帧信息,从而大大减less空间。 例外情况也使得难以分析硬实时需求。

在更典型的环境中,代码大小的代价几乎肯定是不相关的,性能因素可能是关键。 您是否使用它们将取决于您的性能要求以及如何使用它们。 在非例外的情况下使用exception可以做出优雅的devise,但是性能成本可能无法用于高性能系统。 实现和相对成本因平台和编译器而异,所以真正理解exception是一个问题的最好方法是分析自己的代码的性能。

通常setjmp()longjmp()

捕捉exception确实有一个不平凡的成本,但对大多数目的来说,这并不是什么大不了的事情。

在Google的C ++代码(除了一些特定于Windows的情况)不使用exception:cfr 指导原则 ,简称:“我们不使用C ++exception”。 从讨论中引用(点击箭头展开url):

我们反对使用例外的build议不是基于哲学或道德的理由,而是基于实践的。 因为我们想要在Google上使用我们的开源项目,如果这些项目使用exception,很难这样做,所以我们还需要针对Google开源项目中的exception提出build议。 如果我们不得不从头开始,那么事情可能会有所不同。

此规则不适用于其他语言(如Java和Python)中的Google代码。

关于性能 – 稀疏使用例外可能会有微不足道的影响,但不要滥用它们。

我亲眼目睹了Java代码的执行比它可能的要差两个数量级(花费了大约100倍的时间),因为在重要的循环中使用了exception,而不是更多的标准。

像Objective-C运行时的一些运行时有零成本的64位exception。 这意味着它不需要花费任何东西来inputtry块。 但是,在引发exception时,这是相当昂贵的。 这遵循“针对一般情况进行优化”的范例 – exception意味着例外,所以最好在没有exception情况下快速处理情况,即使这样做的代价是明显较慢的exception情况。