问题背景:
为了确保更可靠和结构化的错误处理,C++ 引入了异常处理机制,而不是使用返回代码。随着时间的推移,语法得到了扩展,出现了 noexcept 类型的说明符,用于控制函数抛出异常的取消。
问题:
不正确地处理异常常会导致内存泄漏、未定义行为或应用程序崩溃。如果不考虑从构造函数、析构函数或资源操作中抛出异常,则程序状态会出现严重问题。
解决方案:
基本语法是使用 try-catch。异常可以是任何类型,但建议自 std::exception 继承用户自定义异常。关键字 noexcept(C++11+)指示函数不应抛出异常;从 noexcept 函数抛出的异常会导致 std::terminate()。
代码示例:
#include <iostream> #include <stdexcept> void func() noexcept(false) { throw std::runtime_error("Error!"); } int main() { try { func(); } catch(const std::exception& ex) { std::cout << ex.what(); } }
关键特性:
在析构函数中抛出异常是可以的吗?
不可以,在栈展开期间从析构函数抛出异常会导致 std::terminate()。在析构函数中需要捕获异常。
如果从 noexcept 函数抛出异常,会发生什么?
将调用 std::terminate,程序将异常终止。noexcept 是严格契约。
可以按值捕获异常吗?这有什么危险?
可以按值捕获,但对象会被复制(object slicing)。建议使用 const &。
代码示例:
try { throw std::out_of_range("err"); } catch (const std::exception& e) { /* ... */ }
代码在资源的析构函数中抛出了异常;在程序异常终止时,栈展开不正确,资源成为泄漏。
优点:
缺点:
关键方法标记为 noexcept,析构函数在内部处理所有异常。应用了按引用捕获,所有错误都被记录。
优点:
缺点: