7.4 类型系统的支持
解决 C++ 中的逻辑和性能问题的传统方法是将计算从运行期挪到编译期。显然,将异常与静态类型系统集成的可能性在 1980 年代被认真考虑过,后来又反复被重新考虑。如果异常是函数类型的一部分,那么程序就会有更好的类型检查,函数就更能自我描述,异常处理也更容易优化。
不将异常作为类型系统的一部分的一个主要原因是,如果异常是函数类型的一部分,那么对该函数可能抛出的异常集的更改将要求所有调用该函数的函数重新 编译。在一个大多数主要程序都由许多单独开发的库组成的世界里,这将导致灾难性的脆弱,及无法管理的相互依赖 [Stroustrup 1994]。
函数指针方面也有相关的明显问题。在大多数主要的 C++ 程序中都有很多 C 风格的代码,现在仍然如此。C 风格的泛型代码(例如,qsort
的比较函数参数)和回调(例如,在 GUI 中)的主要参数化机制均会用到函数指针。
如果我需要一个指向函数的指针,并且异常是类型系统的一部分,那么,我要么决定始终从所指向的函数中获取异常,要么不接受异常,要么以某种方式处理 这两种选择。除非将对类型查询的支持或基于异常的重载添加到语言中,否则都很难两者兼顾。确定了要接受哪种类型函数指针参数后,我现在必须调整调用函数中 的错误检查方式以匹配所接受的函数指针类型。即使这些可以在 C++ 语言中处理,也将影响与 C 的交互:这时如何将指向 C++ 函数的指针传递给 C?例如,如何处理从 C 中回调依赖异常的 C++ 的函数?显然,C++ 函数中的异常不会消失,因此我们将有四种选择:错误码、编译期检查的异常(例如 [Sutter 2018b])、当前异常和 noexcept
。只有当前的异常和非本地错误码不会影响类型系统或调用约定(ABI 接口)。幸运的是,很少有函数需要两个函数指针,否则我们将面临选择 16 种方案的风险。因此,如果接受异常类型系统(就当前的异常而言),混乱将是全方面的。
在现代 C++ 中,此类问题将以其他回调机制的不同形式继续存在,例如具有要被调用的成员函数的对象、函数对象和 lambda 表达式。
我的结论(得到 WG21 的认可)过去和现在都是,在 C++ 的静态类型系统中添加异常会导致系统脆弱、代码复杂性显著增加、严重的不兼容性以及与 C 代码交互的问题。这一点在 1989 年就得到了重视。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论