原文
比较D中的异常和错误
什么是D中异常和错误?为什么有区别?为什么D认为可以在不抛
函数内部抛错误
?
抛可抛
简单地说,异常是在正常代码
中不应出现的"异常"
情况.异常
优于其他类型
的错误处理
(如返回错误码
或错误/值
组合)的原因是:要处理异常
.你不处理,别人就会处理.并且默认
是打印出异常
时的状态,然后退出
程序.
注意,最新编译器
有叫@mustUse
的要求必须
处理(可能包含错误
的)返回值
的新功能.
抛
相对昂贵,即应该只在真正异常
时使用它,而不要用来控制
流程.
在D中,只需用要求对象为可抛
的抛
语句即可触发异常或错误
.类似C++
协程的可等待
.
然后可在其他
地方抓它.抓它时,异常
包含生成异常的文件/行
及调用栈层次
位置等异常
的所有信息.美妙
在于可把处理器
放在调用栈
上最需要处理
它的地方.
考虑Web
服务器,你想用异常
处理器处理HTTP
请求部分,只需在有异常
时抛异常
,并在想要处理
的地方
抓它.语言负责
其余工作!
展开栈
语言必须
处理展开栈
.如,如果栈上有带析构器
的结构,则必须调用这些析构器
,否则程序不完整.如果引用计数
的智能指针
在抛异常
时未减少引用
.则一直锁定
着互斥锁
.
还有域保护
语句可帮助正确
设计初化/清理
代码,而不必在域尾
或每个中
语句中清理
.抛异常
时也必须运行它们.
不抛函数
不抛
函数是不让异常
逃逸出函数的函数
.即你必须
处理所有本函数
内或调用的抛函数
内抛的异常
.不抛
函数目的是通知
编译器可省略抛异常
的清理代码
.
从而输出
更少代码,更大优化,使不抛
函数比抛函数
更好.
错误的展开栈
但是,仍允许不抛
函数抛错误
.
原理是编译器
仍然省略了清理异常
的代码,而抓到错误
时,则禁止
继续跑程序
.否则,程序
显然无效.抛/抓
错误类似goto
语句.
以下示例和输出演示如何跳过清理
代码:
可抓错误
,并按控制流
机制来用.如,想从常见的越界访问数组
中恢复
.但是可能未正确
清理栈帧,即栈上未解锁
互斥锁或引用递减
等.
总之,程序状态不确定.继续
执行会损坏程序数据,或崩溃应用.
如何处理错误
唯一的例外(异常)
(双关语
),是测试代码时.单元测试和合同
中,语言保证正确展开抛断定错误
的栈.
根据经验,错误
为编程错误(即,程序员犯的错),而异常
为环境/用户
错误.
如果抓到错误,正确操作是执行扫尾/清理
操作,并确保操作为确定
状态.再退出程序.