Google、Mozilla、Qt、LLVM 这几家的规范是明确禁用异常的
链接:https://www.zhihu.com/question/22889420/answer/22975569
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
整个 C++ exception 的行为在常见语言中是最奇葩的, 因为这个语言特性与 C++ 其他 feature(特别是确定性析构) 格格不入。在 C++ 中全面铺开使用异常会遇到其他语言中不存在的问题。
从网上容易找到一些公司/组织的C++编码规范,其中至少 Google、Mozilla、Qt、LLVM 这几家的规范是明确禁用异常的。前面三家或许可以用代码历史包袱、程序员C++水平参差不齐、保证可移植性等理由来解释,但是 LLVM 却不同。首先,LLVM 在 2003 年才发布第一版,是个21世纪的新项目,没什么历史包袱;更重要的是,LLVM 的作者同时也开发了 clang 这个 C++ 编译器,用 C++ 写 C++ 编译器的程序员恐怕是 C++ 程序员里对语言掌握得最好的那一批,如果他们都在项目中明确地禁用异常,这意味着什么呢?注意到 clang 源码已经用上了 C++11,那么“考虑移植性照顾老host编译器”这条理由似乎也不成立了。
C++ 引入异常的原因之一是为了能让构造函数报错(析构函数不能抛异常这是大家都知道的常识),毕竟构造函数没有返回值,没有异常的话调用方如何得知对象构造是否成功呢?但是编译器/标准库为了让构造函数能抛异常却是麻烦重重:
- 数组元素构造时抛异常,前面已经构造好的元素要析构,还没有构造的元素不能析构。
- 构造函数的初始化列表里抛异常,前面已经构造好的成员和基类子对象要析构,还没有构造的成员则不能析构。而且这个异常捕获之后必须重新抛出(编译器强制),因为C++不允许“半吊子”构造的对象存在。
- 多继承中某个基类的构造函数抛异常,那么已经构造好的基类子对象要析构,还没有构造的基类子对象则不能析构。虚拟继承,虚基类只能析构一次,你慢慢想吧。
- 函数实参对象构造时抛异常,那么多个实参中已经构造好的实参对象要析构,尚未构造的实参对象不能析构。
- std::vector 在 resizing 的时候某个元素的拷贝发生异常,那么前面已经拷贝的元素要析构,尚未拷贝的元素则不必也不能析构,去看 gcc vector::_M_insert_aux 的代码有多麻烦。
(注脚:C++ 引入异常的另一个原因是让 dynamic_cast<Derived&>(baseReference) 能报错,因为没有 null reference。还有一个原因是让 overloaded operator 能报错,毕竟 operator 的返回类型往往无法包含 error code,例如 operator=() 返回的是 Type&。C++ 也是唯一一个变量赋值有可能会抛异常的语言,例如 Person s; s = getPersonById(someId);,那么即便 getPersonById() 不抛异常也不能保证上一句赋值不抛异常。)
(注脚2:C++ 引入异常的政治原因是 Ada 支持异常,而 Ada 是 DoD 的指定官方语言,如果 C++ 不支持异常,那么 AT&T 贝尔实验室就不能拿 C++ 做 DoD 的项目。)
C++ 编译器要随时提防调用某个函数 foo 会抛异常,这会阻止一些优化,也会产生很多累赘的代码(随时准备析构那些调用 foo 函数前已经构造好的栈上对象)。因此 C++11 的 noexcept 应该大力推广。
C++ 的 exception specification 也很鸡肋,它不像 Java 那样在编译期检查(Java 似乎也流行使用 unchecked exception 了),而是在运行期检查,而且违反的后果是直接终止程序,那谁敢用啊?还不如用代码注释呢。有的编译器干脆就只支持语法而不实现功能(Exception Specifications)。C# 也不支持 exception specification,可见这是一项无用的语言特性,算是编程语言发展历史上走的弯路吧,可惜 Java/C++ 掉坑里了。
其他支持异常的语言几乎都有 GC,抛异常就抛了,不用担心析构,反正GC管着。只有 C++ 才有 exception safety 需要考虑,其他支持异常的语言都没有这一概念。
而且 Java 的 try-with-resource,C# 的 using,Python 的 with 在管理 function local scope 对象的生命期(资源、lock 释放)方面不比 RAII 麻烦。Go defer 要差一些,它是 function 级,不是 block 级,只能对付 return。 不过反正 Go 也没异常,有点小坑罢了,把函数写短点就能绕过。
RAII 的优势在于将对象的生命期管理与其他资源(锁、文件、网络连接等等)的管理整合,然后通过 smart pointers 一并解决了,这是 C++ 独一无二的优势。
如果写递归下降的 parser,那么内部用异常来报错似乎是合理的,对外返回一个 error code 即可。
Google、Mozilla、Qt、LLVM 这几家的规范是明确禁用异常的的更多相关文章
- chrome google mozilla firefox bookmarks import export
chrome导出导入bookmarks 1◆ google帐号 自己申请,脑补 2◆ google访问 脑补 suggestion Lantern 3◆ 步骤 4◆ 导入 sample ...
- C++ 异常机制分析(C++标准库定义了12种异常,很多大公司的C++编码规范也是明确禁止使用异常的,如google、Qt)
阅读目录 C++异常机制概述 throw 关键字 异常对象 catch 关键字 栈展开.RAII 异常机制与构造函数 异常机制与析构函数 noexcept修饰符与noexcept操作符 异常处理的性能 ...
- qt 工具下的dump工具导出文档出现异常解决方案
今天一直认为qt环境下的dumpcpp 和dumpdoc两个导出工具很好用,可以今天在导出MSChart组件的类方法文档时,虽然导出成功了,但是导出的结果却是令人失望.自己也不知道如何能够正确导出,就 ...
- [Qt 踩坑] 设置背景就卡退 报错 异常结束或者crashed 0xFFFFFFFF
#开始 我现在是带着崩溃得心情写博客的 这个估计是我遇到的最混蛋的bug 我试图用Qt写个小程序 然后给窗口添加一个背景 就像这样 先不管我那个路径的问题 只要写了那个代码,就一定出错 删除了一点事情 ...
- 开发人员的福音:微软、谷歌、Mozilla将他们所有的web API文档放在同一个地方
Tips 原文作者:Liam Tung 原文地址:Developers rejoice: Microsoft, Google, Mozilla are putting all their web A ...
- Google不做坏事吗?
说中国足球为什么冲不出亚洲,那是因为咱中国人太文气,足球是种“斗牛士”式的游戏,得玩的有点儿“野蛮”色彩.记得以前在英国的时候,遇上联赛,晚上大街小巷全民皆兵,曼切斯特队的粉丝在街道一边酒吧里,利物浦 ...
- Google, FaceBook, Amazon 加州求职记 (转)
http://blog.csdn.net/ithomer/article/details/8774006 http://www.myvisajobs.com 一年多前,出于显而易见的原因,下定决心肉身 ...
- Qt Assistant 工作机制
Qt Assistant 是Qt 的助手,我们在看帮助的时候要用到的,它可以记住上一次你访问的位置. 1. 所以在你调用Qt Assistant为我们自己的程序写help的时候要记得修改qhcp配 ...
- 识别真假搜索引擎(搜索蜘蛛)方法(baidu,google,Msn,sogou,soso等)
http://www.useragentstring.com/pages/useragentstring.php 今天分析研究了两个网站的 Apache 日志,分析日志虽然很无聊,但却是很有意义的事情 ...
随机推荐
- php如何openssl_encrypt加密解密
最近在对接客户的CRM系统,获取令牌时,要用DES方式加密解密,由于之前没有搞错这种加密方式,经过请教了"百度"和"谷歌"两个老师后,结合了多篇文档内容后,终于 ...
- [NOI2003]逃学的小孩(树的直径)
[NOI2003]逃学的小孩 题目描述 Chris家的电话铃响起了,里面传出了Chris的老师焦急的声音:"喂,是Chris的家长吗?你们的孩子又没来上课,不想参加考试了吗?"一听 ...
- js使用offsetHeight获取div高度为0的问题
今晚试了好久没弄出来,后来获取子一层的div就能获取到高度了 我的情况是这样的:我在最外面写一个<div id="mainBody">, 里面写bootstrap的d ...
- hibernate session.save()和session.persist()的区别
save()需要返回一个Serialzable的实现类,因此执行这个方法时会马上插入到数据库 而persist()不会立即插入到数据库. "当我们封装一个长会话流程的时候,persist() ...
- 【AHOI2013】【BZOJ3238】差异
Description Input 一行,一个字符串S Output 一行.一个整数.表示所求值 Sample Input cacao Sample Output 54 HINT 2<=N< ...
- android 视频开发2分之2(仿美拍,糗百)
上一篇写了分段录制和合并视频.这一篇则是选择视频,然后截断视频. 1.从sdcard中找到视频资源: 2.分析视频,拿到你须要的帧数当你的图片.(我的是依据參数来算的多少秒1帧的图片,通常是1秒1帧来 ...
- WireGuard 隧道的安装和使用,测试地址 ca.6tu.me
WireGuard 端到端平等的网络隧道,测试地址 ca.6tu.me --------------------------------------------- 服务器:远程 Ubuntu18 , ...
- 关于nios 中printf 的问题
在nios中,有printf的程序,在线调试没有什么问题,但是下到flash里面,程序跑了一段时间就死掉了!JTAG_UART是阻塞式输出,他只是将数据输出到buffer中,等待你上位机读取,当你的b ...
- 酱油记:GDKOI2018
GDKOI2018,走出机房的第六场考试 DAY0 这一次GDKOI,第一次在广州二中考,第一次住在柏高酒店(住宿条件杠杠的!),晚上就到对面的万达广场吃了顿烤肉,到老师那里开会,然后就回酒店睡了 D ...
- CentOS7 启动[root@localhost ~]# systemctl start docker Job for docker.service failed because the control process exited with error code. See "systemctl status docker.service" and "journalctl -xe" for de
1).在linux虚拟机上安装docker步骤:1.检查内核版本,必须是3.10及以上uname ‐r2.安装dockeryum install docker3.输入y确认安装4.启动docker[r ...