C++异常处理机制的弊端
C++是C语言的升级版,引入了很多高级语言特性,其中就包括异常处理机制。
跟其他语言类似,C++使用try catch throw关键字处理异常。一个简单的C++异常处理程序,类似这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #include <iostream> using namespace std;
double division(int a, int b) { if( b == 0 ) { throw "Division by zero condition!"; } return (a/b); }
int main () { int x = 50; int y = 0; double z = 0; try { z = division(x, y); cout << z << endl; } catch (const char* msg) { cerr << msg << endl; }
return 0; }
|
看起来非常不错,异常被捕获了。编译运行该程序
1
| Division by zero condition!
|
尽管预定义了很多标准异常,但是,现实中面对复杂业务场景,异常处理变得很蹩脚。
先看下面这个我根据真实的案例模拟的小程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| #include <iostream> #include <exception> using namespace std;
struct MyException : public exception { const char * what () const throw () { return "C++ Exception"; } }; struct MyException2 : public exception { const char * what () const throw () { return "C++ Exception2"; } }; struct MyException3 : public exception { const char * what () const throw () { return "C++ Exception3"; } };
void efun1() { throw MyException(); }
void efun2() { throw MyException2(); } void efun3() { try{ efun1(); efun2(); }catch(...) { throw MyException3(); } }
void efun() { try { efun3(); }catch(...) { throw; } } int main() { try { efun(); } catch(std::exception& e) { //Other errors std::cout << "Std Exception caught" << std::endl; std::cout << e.what() << std::endl; } }
|
其中,efun3 调用efun1,efun2 会抛出MyException3(). 那么main调用efun3所捕获的异常将是MyException3(), 而不是efun1异常MyException1()。 也就是说,MyException1被MyException3覆盖了。
你可能会说,efun3 不应该抛出自己的异常,只需要catch什么就throw什么。 这当然可以解决部分问题。但现实的场景往往是复杂的,
1 2 3 4 5 6 7 8 9
| void efun3() { efun1(); //some IO operation efun2() //memory allocation.. ... //call 3rd-party api }
|
可见,为了完美捕获异常,代码作者需要非常小心,而且可读性变差。而维护代码的代价也是不小。所以,干脆不要使用异常处理。
C++不使用异常处理
因为已经有谷歌背书,所以我说话的底气也足了。谷歌C++代码规范
关于构造函数异常的处理,并不是问题。你没必要非得在构造函数里面干那些抛异常的事情。
当然没了异常处理,你的log 和 error code也需要好好设计才是。