try-catch 块异常处理
try-catch
块是异常处理的核心机制,它允许程序在发生异常时捕获并处理这些异常,而不是让程序崩溃。
基本结构
-
try
块:try
块中包含可能抛出异常的代码。如果这段代码正常执行,那么后续的catch
块将不会执行。
-
catch
块:catch
块用于捕获并处理特定类型的异常。可以有多个catch
块来处理不同类型的异常。
示例代码
try {
// 尝试执行的代码,可能会抛出异常
riskyFunction();
} catch (const SpecificException& e) {
// 处理 SpecificException 类型的异常
std::cerr << "Caught SpecificException: " << e.what() << std::endl;
} catch (const AnotherException& e) {
// 处理 AnotherException 类型的异常
std::cerr << "Caught AnotherException: " << e.what() << std::endl;
} catch (...) {
// 处理所有其他类型的异常
std::cerr << "Caught an unknown exception" << std::endl;
}
详细说明
-
try
块:- 所有可能抛出异常的代码都应该放在
try
块中。
- 所有可能抛出异常的代码都应该放在
-
catch
块:catch
块可以捕获特定类型的异常。如果有多个catch
块,它们将按照定义的顺序进行匹配。- 每个
catch
块可以访问异常对象,通常通过引用传递。这样可以调用异常对象的成员函数(如what()
)来获取更多信息。
-
捕获所有异常:
- 使用
catch (...)
可以捕获所有未被前面的catch
块处理的异常。这通常作为最后一个catch
块,以确保所有异常都能被处理。
- 使用
-
异常的传播:
- 如果一个
catch
块没有捕获异常,异常会传播到外层的try-catch
块中。如果最终没有被捕获,程序将终止。
- 如果一个
异常处理的注意事项
-
避免在
try
块中进行不必要的操作:- 只将可能抛出异常的代码放在
try
块中,以避免不必要的性能开销。
- 只将可能抛出异常的代码放在
-
确保资源安全:
- 使用 RAII(Resource Acquisition Is Initialization)原则,确保资源在构造函数中获取,在析构函数中释放。这样可以保证即使发生异常,资源也能被正确释放。
-
避免异常被吞没:
- 在
catch
块中,确保不忽略异常。如果不需要处理某个异常,可以将其重新抛出或记录日志。
- 在
-
使用异常链:
- 当在
catch
块中抛出新的异常时,可以使用std::throw_with_nested
(C++17 引入)来保留原始异常的信息。
- 当在
-
避免在构造函数中直接使用
throw
:- 构造函数中直接抛出异常可能导致对象状态不一致。使用
std::make_unique
或std::make_shared
等智能指针可以帮助管理资源。
- 构造函数中直接抛出异常可能导致对象状态不一致。使用
异常链示例
try {
riskyFunction();
} catch (const SpecificException& e) {
std::cerr << "Caught SpecificException: " << e.what() << std::endl;
throw; // 重新抛出当前异常
} catch (const AnotherException& e) {
std::cerr << "Caught AnotherException: " << e.what() << std::endl;
throw; // 重新抛出当前异常
} catch (...) {
std::cerr << "Caught an unknown exception" << std::endl;
throw; // 重新抛出当前异常
}