返回信息流看 tensorflow 源码有一段时间,最近用的时候突然发现 tensorflow 没有用异常的,所有的检查都是类似于 c 的方式,写 CHECK 宏然后报错退出。c++ 既然有一场异常,为什么不用呢? 和用宏的这种方式相比,异常有什么劣势么?
这是一条镜像帖。来源:北邮人论坛 / cpp / #93341同步于 2016/9/9
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖
关于用不用C++ 异常的问题
hyx2011
2016/9/9镜像同步10 回复
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
【 在 skcxy 的大作中提到: 】
: 最明显的一点是,使用c++异常机制会牺牲一定的效率。所以好多项目会主动关闭c++异常机制。
: 通过『我邮2.0』发布
C++的异常有好几种实现方式。Linux上基本上已经用“零代价”的Itanium ABI了。在Windows上,还有SJLJ(SetJmp/LongJmp)、SEH(structured exception handling)等。
Itanium ABI的异常处理是在发生异常的情况下,通过每个stack frame里的返回地址(即PC位置)反查出“当前逻辑上对应的C++的位置”,以此推断出“catch语句的位置”。由于PC提供了全部的信息,只要不抛出异常,就不会有效率影响,效率和“catch语句不存在的情况”是一样的。这就是为什么它被称为“零代价”的原因。
SJLJ不是“零代价”的。SJLJ方式中,函数调用之前,要用setjmp保存所有的寄存器,发生异常的时候用longjmp恢复寄存器。这种方式,即使没有发生异常,也要进行一次setjmp,所以不是零代价。而现代的机器动辄几十个寄存器,所以代价还不小。
SEH是Windows下的“零代价”异常处理方法。
但是,至于异常用不用,主要是二进制兼容性的问题。Linux下不用说,大家都用一致的ABI(就算ABI变过,都是开源软件,重新编译一下就可以),GCC一统天下,GCC/Clang等C/C++语言编译器也会生成兼容.eh_frame异常处理信息,C++异常可以正常穿越C函数。所以Linux下不用怎么担心。
但Windows下,各种编译器的ABI都不一样,使用异常就要特别小心了。甚至仅仅是“在Windows下使用C++语言”这一个决策都必须小心。不同的编译器,不兼容的也许不仅仅是异常处理,甚至直接的函数调用都成问题。如果你的是一个独立的程序,那么只要自己能工作就可以了;如果是给别人用的库,就要考虑编译器的区别了。另外,选用别人提供的库的时候也要看看他们的库(二进制形式,如dll)是兼容什么编译器的。
总之,二进制兼容性才是最大的问题。
【 在 hyx2011 的大作中提到: 】
: 看 tensorflow 源码有一段时间,最近用的时候突然发现 tensorflow 没有用异常的,所有的检查都是类似于 c 的方式,写 CHECK 宏然后报错退出。c++ 既然有一场异常,为什么不用呢? 和用宏的这种方式相比,异常有什么劣势么?
C方式的“用检查errno的方式报告错误”是个很差劲的方法,效率不如异常处理,可读性也很差。但却是最传统的,关键是机制简单:反正只有一个全局变量(如果是thread-local变量就更好了),不需要编译器怎么配合;对人来说,模型很简单,对习惯了全局变量的C程序员来说,不容易让人误会。又或者,我觉得他们也许不愿意陷入各种不兼容性当中吧。
“异常处理”的优势看我上一贴。以及:https://bbs.byr.cn/#!article/CPP/92825
受教了,有机会在仔细研究下。谢暖神指点[em21]
【 在 nuanyangyang (暖羊羊) 的大作中提到: 】
: C++的异常有好几种实现方式。Linux上基本上已经用“零代价”的Itanium ABI了。在Windows上,还有SJLJ(SetJmp/LongJmp)、SEH(structured exception handling)等。
: Itanium ABI的异常处理是在发生异常的情况下,通过每个stack frame里的返回地址(即PC位置)反查出“当前逻辑上对应的C++的位置”,以此推断出“catch语句的位置”。由于PC提供了全部的信息,只要不抛出异常,就不会有效率影响,效率和“catch语句不存在的情况”是一样的。这就是为什么它被称为“零代价”的原因。
: SJLJ不是“零代价”的。SJLJ方式中,函数调用之前,要用setjmp保存所有的寄存器,发生异常的时候用longjmp恢复寄存器。这种方式,即使没有发生异常,也要进行一次setjmp,所以不是零代价。而现代的机器动辄几十个寄存器,所以代价还不小。
: ...................
通过『我邮2.0』发布