异常处理的基本操作
C++中通过下面的三个关键字来是实现异常处理
try
用于标记可能出现异常的代码块,被try标记的代码块称为保护代码
throw
当在保护代码中遇到异常时,可以通过throw关键字来将异常抛出
catch
跟在保护代码后面,catch关键字能够捕获throw抛出的异常,并根据异常的类型进行不同的处理
示例
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
| #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; }
|
C++异常类
throw和catch既可以抛出和捕获基础类型的异常,也可以使用C++预定义的异常类,这些异常类有统一的的接口,便于我们进行异常的捕获和处理。
C++预定义的异常类包括:
std::exception:所有标准异常的基类。
std::bad_alloc:内存分配失败时抛出。
std::bad_cast:动态类型转换失败时抛出。
std::bad_typeid:使用typeid运算符失败时抛出。
std::bad_exception:在函数声明中使用了异常规格,但抛出了未列出的异常时抛出(C++11已弃用)。
std::logic_error:逻辑错误异常基类,包括:
std::domain_error:数学域错误,如sqrt(-1)。
std::invalid_argument:无效参数错误。
std::length_error:超出允许长度的错误。
std::out_of_range:范围错误,如访问vector的非法索引。
std::runtime_error:运行时错误异常基类,包括:
std::overflow_error:上溢错误。
std::range_error:范围错误(与std::out_of_range不同,用于其他情况)。
std::underflow_error:下溢错误。
上面的异常类最常使用的核心接口.what(),返回const char *,用于说明异常的情况。
标准异常类的示例
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
| #include <iostream> #include <stdexcept> using namespace std; void testLogicError() { throw invalid_argument("Invalid argument error!"); } void testRuntimeError() { throw out_of_range("Out of range error!"); } int main() { try { testLogicError(); } catch (const logic_error& e) { cout << "Caught a logic_error: " << e.what() << endl; } try { testRuntimeError(); } catch (const runtime_error& e) { cout << "Caught a runtime_error: " << e.what() << endl; } return 0; }
|
此外,还可以通过继承std::exception并重载what来实现自定义的异常类。
自定义异常类的示例
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
| #include <iostream> #include <exception> #include <string> using namespace std; class MyException : public exception { public: MyException(const string& message) : message_(message) {} virtual const char* what() const noexcept override { return message_.c_str(); } private: string message_; }; void testCustomException() { throw MyException("Custom exception occurred!"); } int main() { try { testCustomException(); } catch (const MyException& e) { cout << "Caught a MyException: " << e.what() << endl; } catch (const exception& e) { cout << "Caught an unknown exception: " << e.what() << endl; } return 0; }
|
noexcept
从C++11开始,可以使用noexcept修饰函数,声明函数不会抛出任何异常,这有利于编译器做更多的优化
此外,noexcept还可以作为运算符,传入函数来验证某个函数是否被noexcept修饰
1 2 3 4 5 6
| void may_throw(); void no_throw() noexcept; int main() { noexcept(may_throw()); noexcept(no_throw()); }
|
类的析构函数默认是noexcept的