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一直到达主函数,并退出.

可抓错误,并按控制流机制来用.如,想从常见的越界访问数组恢复.但是可能未正确清理栈帧,即栈上未解锁互斥锁或引用递减等.

总之,程序状态不确定.继续执行会损坏程序数据,或崩溃应用.

如何处理错误

唯一的例外(异常)(双关语),是测试代码时.单元测试和合同中,语言保证正确展开抛断定错误的栈.
根据经验,错误为编程错误(即,程序员犯的错),而异常环境/用户错误.
如果抓到错误,正确操作是执行扫尾/清理操作,并确保操作为确定状态.再退出程序.

posted @   zjh6  阅读(71)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示