前言
异常有三种方式传递到catch子句:通过指针(by pointer),通过传值(by value)或通过引用(by reference)。
by pointer
用指针来传递异常理论上来说是效率最高的,因为只有它不用copy:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class exception { ... };
void someFunction(){
static exception ex; // 异常对象
...
throw &ex; // 抛出一个指针,指向 ex
...
}
void doSomething(){
try {
someFunction(); // 抛出一个 exception*
}
catch (exception *ex) { // 捕获 exception*;
... // 没有对象被拷贝
}
}
逻辑上看起来没错,但老是有人忘了下述约定:定义异常对象时,必须确保程序控制权离开抛出指针的函数后对象仍然继续生存,否则catch的对象已被析构。具体来说,当我们用指针抛出异常,必须确保该异常是一个static对象或者位于heap中。
但这两种情况又引入了新的问题:你不知道该在何时删除它们。中的对象不删除必然会导致资源泄漏,而全局变量无法删除,否则程序行为将不可预测。
c++不鼓励通过指针传递异常,四大标准异常:bad_alloc、bad_cast(dynamic_cast失败)、bad_typeid(dynamic_cast操作空指针)、bad_exception(unexpected异常)均不是指向对象的指针,因此你必须通过值或引用来捕获。
by value
值捕获有两大缺陷:
- 两次拷贝
- slicing problem(由于拷贝静态类型引起)
1 | class exception { |
传值模式在何时都只会调用基类函数,完全丧失了多态性质。
by reference
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16void someFunction(){
...
if (a validation 测试失败) {
throw Validation_error();
}
...
}
void doSomething(){
try {
someFunction();
}
catch (exception& ex) {//引用捕获
cerr << ex.what(); //Validation_error::what(),
...
}
}
总结
如果你通过引用捕获异常(catch by reference),有优点如下:
- 无需担心对象已被析构或者不确定对象何时需要删除(by pointer缺点)
- 无需拷贝2次且丧失多态性质(by value缺点)