程序必须要能面对错误情况给出反应
一、系统错误
考虑你写了一求数两个整数最大公约数的函数int gcd(int a, int b);
其中a和b都不可以为0
二、处理方法
函数一开始就判断a,b两个是否有0出现
你的代码开始的地方变成了下面的样子
- int gcd(int a, int b)
- {
- //(1)使用断言
- assert(a!= 0 && b!=0);
- // 这里开始干正事
- }
上面代码使用断言的效果:debug开发模式这里会导致程序死掉。
不过断言只有debug模式才有(release模式会被编译器擦除,写了也等于没写)。
代码的参数者 | 约定 | 原则 |
---|---|---|
gcd代码的作者 | assert | 保证返回值,方便调用; 底层保证效率 |
gcd代码的用户 | 调试环境使用发现错误 | 自己保证别传错误参数 |
二、逻辑错误
考虑你实现了一个json库,用户给你一个字符串,你的json对象就可以根据这个json字符串创建对象,并访问其中的数据:
- CJsonObject json;
- json.CreateFromStr("{\"name\":\"zhangsan\", \"age\":26\"}");//bad json str
上面的json对象需要一个合法的json字符串才能创建,但是传入的字符在整数26右侧多了一个分号。
这是一个非法的字符串,这时候你作为库作者不知道应该怎么处理。你唯一能做的就是把错误暴露出来。
三、两种暴露错误的方式
1 返回错误码
函数返回错误码,调用函数的人检查错误码。代码变成下面这样:
- CJsonObject json;
- int good_json = json.CreateFromStr("{\"name\":\"zhangsan\", \"age\":26\"}");//bad json str
- if(good_json != OK)
- {
- //write log or print some worning to the caller
- return ERROR_JSON;//so many error code
- }
代码参与者 | 约定 | 原则 |
---|---|---|
CreateFromStr的作者 | 负责抛出错误,而不处理错误 | 库作者不知道该如何处理错误 |
CreateFromStr的用户 | 负责发现错误,进而处理错误 | 上层代码保证有效性 |
2 抛出异常
抛出异常之后,库作者需要捕获异常才知道有没有发生错误。代码变成下面这样:
- CJsonObject json;
- try
- {
- json.CreateFromStr("{\"name\":\"zhangsan\", \"age\":26\"}");//bad json str
- }
- catch(exception e)
- {
- //错误处理, write log or print some worning to the caller
- }
代码参与者 | 约定 | 原则 |
---|---|---|
CreateFromStr的作者 | 负责抛出错误,而不处理错误 | 库作者不知道该如何处理错误 |
CreateFromStr的用户 | 负责发现错误,进而处理错误 | 上层代码保证有效性 |
3 返回错误码和抛异常的对比
类型 | 返回错误码 | 抛异常 |
---|---|---|
常用场景 | 操作系统 | json库等中间库 |
优点 | 流程完全可控,对于流程比较复杂的场景可以准确定位每一步,并做出处理 | 代码直观,不用每次都判断 |
缺点 | 导出都是判断错误的代码,代码增长比较严重 | 流程复杂的时候,没有合适的地方捕获,提前捕获用户看不到;适合层级比较少的场景 |