通常,异常不得传播模块边界,例如 Herb Sutters C++ 编码标准(第 62 项)中所述。当使用不同的编译器或仅使用编译器设置编译时,这可能会崩溃。
如果是动态链接库,我可以理解这个问题。但我想知道它是否也适用于静态库。就上述规则而言,静态库是模块吗?如果库是用其他编译器设置(例如对齐)编译的,如果从静态库中抛出异常并在应用程序中捕获,程序可能会崩溃?
通常,异常不得传播模块边界,例如 Herb Sutters C++ 编码标准(第 62 项)中所述。当使用不同的编译器或仅使用编译器设置编译时,这可能会崩溃。
如果是动态链接库,我可以理解这个问题。但我想知道它是否也适用于静态库。就上述规则而言,静态库是模块吗?如果库是用其他编译器设置(例如对齐)编译的,如果从静态库中抛出异常并在应用程序中捕获,程序可能会崩溃?
通常,静态库必须由相同的编译器和相同的编译器设置(大部分)编译才能与交付物(动态库或可执行文件)兼容。
然后,您可以在静态库的边界之外抛出异常,因为它与您的编译器生成的一组 .obj 文件没有太大区别。而且您显然可以在不同的 .obj 模块之间引发异常。
编辑:
总结评论:
Herb Sutters 的描述也适用于静态库:
C++ 异常处理没有普遍的二进制标准。除非您控制用于构建双方的编译器和编译器选项,否则不允许异常在两段代码之间传播;否则,模块可能不支持异常传播的兼容实现。通常,这归结为: 不要让异常跨模块/子系统边界传播。
这取决于 Herb 所说的“模块”是什么意思。这些问题不仅涉及异常;他们可以使用 C++ 接口处理任何事情。
当异常跨越作为同一组件的一部分编译的源的翻译单元边界时,当然没有问题。在组件之间,如果它们都是同一个应用程序的一部分,并且您确保它们都使用相同的编译器进行编译,具有相同的编译器选项,那么它可能是安全的,尽管在动态库之间交叉时可能会出现问题,具体取决于库是如何加载的。(一般来说,这只是 Unix 系统上的问题,其中动态加载的组件中符号的可见性由传递给动态加载器的选项控制。)作为一般规则:安排让所有应用程序都使用相同的编译器编译器和相同的编译器选项,并且您在应用程序中应该没有真正的问题(尽管您可能必须确保所有动态组件都被显式加载,至少在 Unix 下)。在您正在加载或被“外国”软件加载的“应用程序”之间,Herb 的限制还远远不够。在实践中,您在应用程序之间交叉的接口必须在 C 中定义。并且可能仍然存在限制,这取决于您的代码的加载方式以及正在使用哪些其他动态加载的组件。
静态链接将消除有关如何加载库的问题,但不会改变其他任何内容。