|
程序错误通常分为两种类别:由编程失误导致的逻辑错误,例如“索引超出范围”错误。 以及超出程序员控制范围的运行时错误,例如“网络服务不可用”错误。 在 C 样式的编程和 COM 中,错误报告的管理方式是返回一个表示错误代码或特定函数的状态代码的值,或者设置一个全局变量,调用方可以在每次执行函数调用后选择性地检索该变量来查看是否报告了错误。 例如,COM 编程使用 HRESULT 返回值将错误传达给调用方。 Win32 API 提供 GetLastError 函数用于检索调用堆栈报告的最后一个错误。 在这两种情况下,都需要由调用方识别代码并相应地做出响应。 如果调用方未显式处理错误代码,则程序可能会在不发出警告的情况下崩溃。 或者,它可能会继续使用错误的数据执行,并生成错误的结果。
新式 C++ 中优先使用异常的原因如下:
异常会强制调用代码识别并处理错误状态。 未经处理的异常会停止程序执行。
异常跳转到调用堆栈中可以处理错误的位置。 中间函数可以让异常传播。 这些函数不必与其他层协调。
引发异常后,异常堆栈展开机制将根据妥善定义的规则销毁范围内的所有对象。
异常可以在检测错误的代码与处理错误的代码之间实现明确的分离。
以下简化示例演示了 C++ 中引发和捕获异常的必要语法。
#include <stdexcept>
#include <limits>
#include <iostream>
using namespace std;
void MyFunc(int c)
{
if (c > numeric_limits< char> ::max())
throw invalid_argument("MyFunc argument too large.");
//...
}
int main()
{
try
{
MyFunc(256); //cause an exception to throw
}
catch (invalid_argument& e)
{
cerr << e.what() << endl;
return -1;
}
//...
return 0;
}
C++ 中的异常类似于 C# 和 Java 等语言中的异常。 在 try 块中,如果引发某个异常,类型与该异常的类型匹配的第一个关联 catch 块将捕获该异常。 换言之,执行将从 throw 语句跳转到 catch 语句。 如果未找到可用的 catch 块,则调用 std::terminate 并且程序会退出。 在 C++ 中可以引发任何类型;但是,我们建议引发直接或间接派生自 std::exception 的类型。 在前面的示例中,异常类型 invalid_argument 是在标准库的 <stdexcept> 头文件中定义的。 C++ 既不提供也不需要 finally 块来确保在引发异常时释放所有资源。 资源采集是使用智能指针的初始化 (RAII) 习语,它提供所需的功能来清理资源。
|
|