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