Skip to content

Commit f9863f7

Browse files
committed
upsomeerrhandling
1 parent 7e168a5 commit f9863f7

File tree

1 file changed

+108
-4
lines changed

1 file changed

+108
-4
lines changed

docs/error_code.md

+108-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,116 @@
1-
# 现代 C++ 中的错误处理 (未完工)
1+
# 现代 C++ 错误处理知多少
22

33
[TOC]
44

5-
## 为什么错误很重要?
5+
## 错误的分类
66

7-
## 提前返回是好习惯!
7+
假设一个函数 `open` 的功能是打开文件。
8+
9+
```cpp
10+
int open(const char *path) {
11+
if (!file_exists(path)) {
12+
// 如果找不到文件怎么办?
13+
}
14+
// 成功找到文件:
15+
return get_handle(path);
16+
}
17+
18+
int main() {
19+
int file = open("file.txt");
20+
21+
char buf[64];
22+
read(file, buf, sizeof buf);
23+
...
24+
}
25+
```
26+
27+
理想情况下,所有的函数都能成功执行,都能正常返回结果……
28+
29+
可现实中,我们不能假设一个程序,永远正确执行(例如文件可能被用户误删除,或者内存不够用等)。
30+
31+
更有甚者,有时错误是计划的一部分(例如文件不存在,则创建一个新文件,而不是将其视为不可修复的错误)。
32+
33+
特别是涉及 IO 操作的任务,出现一些细小错误的情况是很多的。要区分哪些是可以修复的错误,哪些是不可挽回的错误。
34+
35+
例如当网络连接失败时,我们可以重新尝试连接两三次,如果还是不行,那才认为是真的失败了。
36+
37+
因此,我们把错误分为两大类:
38+
39+
- 可恢复错误:不是特别严重的,甚至是计划之中的,经常发生的错误。可以通过一定操作来弥补这类错误,或将其转化为其他不同类型的错误。
40+
- 不可恢复错误:非常严重的错误,或者是发生概率很低平时没必要特殊处理的错误。一旦发生,整个程序都无法继续执行下去,必须全身而退,整个进程或线程都将终止。
41+
42+
### 不可恢复错误
43+
44+
不可恢复错误的处理最简单,我们只需要在被调用者检测到错误的分支中,直接调用 `exit` 函数“终止程序”即可。
45+
46+
```cpp
47+
int open(const char *path) {
48+
if (!file_exists(path)) {
49+
// 找不到文件我就自杀!
50+
exit(1);
51+
// 程序不会执行到此
52+
}
53+
return get_handle(path);
54+
}
55+
56+
int main() {
57+
int file = open("file.txt");
858
9-
TODO
59+
char buf[64];
60+
read(file, buf, sizeof buf);
61+
...
62+
}
63+
```
64+
65+
- 缺点:`exit` 会直接退出整个进程!没有任何给调用者挽回的机会,因此只能用于“不可恢复错误”这个类型。
66+
- 优点:调用者无需做任何判断处理,写起来就好像被调用函数“总是成功”一样,总能返回结果。因为如果被调用者失败的话,他会调用 `exit` 自杀,就不会返回到调用者中了。
67+
68+
> {{ icon.fun }} 小时候看这集变成“码码的萤火虫”了。
69+
70+
### 可恢复错误
71+
72+
有时候,我们对于部分错误,是有挽回机会的,不希望因为一点可以修复的小错误就把整个程序终止掉。
73+
74+
要不要挽回应该由调用者的具体业务决定,而封装良好的 API(`open`)应该忠实地把错误报告给调用者(`main`)。
75+
76+
让调用者来决定要杀了还是抢救,而不是自作主张地直接自杀。
77+
78+
```cpp
79+
int open(const char *path) {
80+
if (!file_exists(path)) {
81+
// 找不到文件,就返回 -1 这个“出错特殊值”代替
82+
return -1;
83+
}
84+
return get_handle(path);
85+
}
86+
87+
int main() {
88+
int file = open("file.txt");
89+
if (file == -1) { // 缺点是 main 里面必须判断返回值是否为“出错特殊值”
90+
// 如果找不到文件,尝试进行处理
91+
create_empty_file("file.txt");
92+
// 重新尝试打开
93+
file = open("file.txt");
94+
if (file == -1) { // 如果还是出错,那就没救了
95+
exit(-1); // 直接自杀
96+
}
97+
}
98+
99+
char buf[64];
100+
read(file, buf, sizeof buf);
101+
...
102+
}
103+
```
104+
105+
### 我该如何抉择
106+
107+
## 调用者与被调用者
108+
109+
`main` 是调用者,`open` 是被调用者。
110+
111+
被调用者函数可能产生错误,也可能正常执行。
112+
113+
## 提前返回是好习惯!
10114
11115
## 异常
12116

0 commit comments

Comments
 (0)