C&C++快速入门
23、异常
1、课程目标
- 理解C++异常处理机制
- 掌握try-catch-throw的使用
- 理解异常与资源管理
- 了解Windows SEH异常
2、名词解释
| 术语 | 说明 |
|---|---|
| try | 异常监视块 |
| catch | 异常处理块 |
| throw | 抛出异常 |
| exception | 标准异常基类 |
| SEH | Windows结构化异常处理 |
| RAII | 资源获取即初始化 |
| 栈展开 | 异常时自动析构局部对象 |
3、代码实现
1. 基础异常处理
#include <iostream>
#include <stdexcept>
using namespace std;
double Divide(double a, double b) {
if (b == 0) {
throw runtime_error("除数不能为零");
}
return a / b;
}
int main() {
cout << "=== 异常处理 ===" << endl << endl;
try {
cout << "10 / 2 = " << Divide(10, 2) << endl;
cout << "10 / 0 = " << Divide(10, 0) << endl; // 抛出异常
cout << "这行不会执行" << endl;
}
catch (const runtime_error& e) {
cout << "捕获异常: " << e.what() << endl;
}
catch (...) {
cout << "捕获未知异常" << endl;
}
cout << "\n程序继续执行" << endl;
return 0;
}
2. 自定义异常类
#include <iostream>
#include <exception>
using namespace std;
class FileException : public exception {
private:
string m_msg;
int m_errorCode;
public:
FileException(const string& msg, int code)
: m_msg(msg), m_errorCode(code) {}
const char* what() const noexcept override {
return m_msg.c_str();
}
int GetErrorCode() const { return m_errorCode; }
};
void OpenFile(const char* filename) {
// 模拟文件打开失败
throw FileException("无法打开文件: " + string(filename), 2);
}
int main() {
cout << "=== 自定义异常 ===" << endl << endl;
try {
OpenFile("nonexistent.txt");
}
catch (const FileException& e) {
cout << "文件错误: " << e.what() << endl;
cout << "错误码: " << e.GetErrorCode() << endl;
}
return 0;
}
3. RAII与异常安全
#include <iostream>
#include <windows.h>
using namespace std;
class FileHandle {
private:
HANDLE m_handle;
public:
FileHandle(const char* filename, DWORD access) {
m_handle = CreateFileA(filename, access, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (m_handle == INVALID_HANDLE_VALUE) {
throw runtime_error("无法打开文件");
}
cout << "文件已打开" << endl;
}
~FileHandle() {
if (m_handle != INVALID_HANDLE_VALUE) {
CloseHandle(m_handle);
cout << "文件已关闭" << endl;
}
}
HANDLE Get() const { return m_handle; }
};
void ProcessFile(const char* filename) {
FileHandle file(filename, GENERIC_READ); // 如果失败会抛异常
// 处理文件...
// 即使这里抛异常,文件也会被正确关闭
}
int main() {
cout << "=== RAII ===" << endl << endl;
try {
ProcessFile("C:\\Windows\\System32\\notepad.exe");
}
catch (const exception& e) {
cout << "异常: " << e.what() << endl;
}
return 0;
}
4. Windows SEH
#include <iostream>
#include <windows.h>
using namespace std;
DWORD FilterException(DWORD code) {
cout << "异常码: 0x" << hex << code << dec << endl;
return EXCEPTION_EXECUTE_HANDLER;
}
int main() {
cout << "=== SEH ===" << endl << endl;
__try {
int* p = nullptr;
*p = 42; // 访问违例
}
__except(FilterException(GetExceptionCode())) {
cout << "捕获SEH异常!" << endl;
}
cout << "\n程序继续" << endl;
return 0;
}
5、课后作业
5.1、作业1:实现异常安全的栈
实现一个栈类,在溢出和下溢时抛出异常。
5.2、作业2:练习SEH
使用SEH处理除零异常。