Appearance
异常处理
异常处理是C++中处理运行时错误的机制。本章将介绍try-catch语句、异常类型、自定义异常和异常安全等概念。
基本异常处理
cpp
#include <iostream>
#include <stdexcept>
using namespace std;
int divide(int a, int b) {
if (b == 0) {
// 抛出异常
throw runtime_error("除数不能为0");
}
return a / b;
}
int main() {
// ============ try-catch基本语法 ============
try {
// 可能抛出异常的代码
int result = divide(10, 0);
cout << "结果: " << result << endl;
}
catch (const runtime_error& e) {
// 捕获特定类型的异常
cerr << "运行时错误: " << e.what() << endl;
}
catch (const exception& e) {
// 捕获标准异常
cerr << "标准异常: " << e.what() << endl;
}
catch (...) {
// 捕获所有其他异常
cerr << "未知异常" << endl;
}
cout << "程序继续执行..." << endl;
return 0;
}标准异常类型
cpp
#include <iostream>
#include <stdexcept>
#include <vector>
using namespace std;
/*
* C++标准异常层次结构:
*
* exception(基类)
* ├── logic_error(逻辑错误,可避免)
* │ ├── domain_error
* │ ├── invalid_argument
* │ ├── length_error
* │ └── out_of_range
* ├── runtime_error(运行时错误,难以避免)
* │ ├── range_error
* │ ├── overflow_error
* │ └── underflow_error
* ├── bad_alloc(内存分配失败)
* ├── bad_cast(类型转换失败)
* └── bad_typeid(typeid操作失败)
*/
void testExceptions() {
// ============ logic_error系列 ============
// invalid_argument:无效参数
try {
throw invalid_argument("参数无效");
}
catch (const invalid_argument& e) {
cout << "invalid_argument: " << e.what() << endl;
}
// out_of_range:越界访问
try {
vector<int> v = {1, 2, 3};
cout << v.at(10) << endl; // 使用at()会抛出异常
}
catch (const out_of_range& e) {
cout << "out_of_range: " << e.what() << endl;
}
// length_error:长度错误
try {
vector<int> v;
v.resize(v.max_size() + 1);
}
catch (const length_error& e) {
cout << "length_error: " << e.what() << endl;
}
// ============ runtime_error系列 ============
// runtime_error:运行时错误
try {
throw runtime_error("运行时发生错误");
}
catch (const runtime_error& e) {
cout << "runtime_error: " << e.what() << endl;
}
// overflow_error:溢出错误
try {
throw overflow_error("数值溢出");
}
catch (const overflow_error& e) {
cout << "overflow_error: " << e.what() << endl;
}
// ============ 内存相关异常 ============
// bad_alloc:内存分配失败
try {
// 尝试分配超大内存
// int* p = new int[1000000000000];
}
catch (const bad_alloc& e) {
cout << "bad_alloc: " << e.what() << endl;
}
}
int main() {
testExceptions();
return 0;
}自定义异常
cpp
#include <iostream>
#include <string>
#include <exception>
using namespace std;
// ============ 自定义异常类 ============
// 继承自exception
class MyException : public exception {
private:
string message;
int errorCode;
public:
MyException(const string& msg, int code = 0)
: message(msg), errorCode(code) {}
// 重写what()方法
const char* what() const noexcept override {
return message.c_str();
}
int getErrorCode() const {
return errorCode;
}
};
// 更具体的异常类
class FileException : public exception {
protected:
string filename;
string operation;
public:
FileException(const string& file, const string& op)
: filename(file), operation(op) {}
const char* what() const noexcept override {
static string msg;
msg = "文件操作失败: " + operation + " on " + filename;
return msg.c_str();
}
const string& getFilename() const { return filename; }
const string& getOperation() const { return operation; }
};
class FileNotFoundException : public FileException {
public:
FileNotFoundException(const string& file)
: FileException(file, "打开") {}
const char* what() const noexcept override {
static string msg;
msg = "文件未找到: " + filename;
return msg.c_str();
}
};
// ============ 使用自定义异常 ============
void processFile(const string& filename) {
if (filename.empty()) {
throw MyException("文件名不能为空", 1001);
}
if (filename == "notfound.txt") {
throw FileNotFoundException(filename);
}
// 模拟文件处理
cout << "处理文件: " << filename << endl;
}
int main() {
// 测试自定义异常
try {
processFile("");
}
catch (const MyException& e) {
cout << "捕获MyException: " << e.what() << endl;
cout << "错误码: " << e.getErrorCode() << endl;
}
try {
processFile("notfound.txt");
}
catch (const FileNotFoundException& e) {
cout << "\n捕获FileNotFoundException: " << e.what() << endl;
}
catch (const FileException& e) {
cout << "\n捕获FileException: " << e.what() << endl;
}
return 0;
}异常安全
cpp
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
// ============ 异常安全级别 ============
/*
* 异常安全级别:
*
* 1. 无异常安全:可能泄漏资源
* 2. 基本保证:异常发生时,对象处于有效状态,不会泄漏资源
* 3. 强保证:异常发生时,状态回滚到操作前(事务语义)
* 4. 不抛出保证:保证不抛出异常
*/
// ============ RAII资源管理 ============
class FileHandle {
private:
FILE* file;
public:
FileHandle(const char* filename, const char* mode) {
file = fopen(filename, mode);
if (!file) {
throw runtime_error("无法打开文件");
}
}
~FileHandle() {
if (file) {
fclose(file); // 自动关闭
}
}
// 禁止拷贝
FileHandle(const FileHandle&) = delete;
FileHandle& operator=(const FileHandle&) = delete;
void write(const string& data) {
if (fputs(data.c_str(), file) == EOF) {
throw runtime_error("写入失败");
}
}
};
// ============ 强异常安全保证 ============
class Stack {
private:
vector<int> data;
public:
void push(int value) {
data.push_back(value); // vector::push_back提供强保证
}
int pop() {
if (data.empty()) {
throw runtime_error("栈为空");
}
int value = data.back();
data.pop_back(); // pop_back不抛出异常
return value;
}
// 强保证:交换操作
void swap(Stack& other) noexcept {
data.swap(other.data); // swap不抛出异常
}
bool empty() const noexcept {
return data.empty();
}
};
// ============ 异常安全的函数 ============
// 使用noexcept声明不抛出异常
void safeFunction() noexcept {
// 保证不抛出异常
cout << "这是一个不抛出异常的函数" << endl;
}
// 条件noexcept
template<typename T>
void conditionalSwap(T& a, T& b) noexcept(noexcept(a.swap(b))) {
a.swap(b);
}
int main() {
// RAII示例
try {
FileHandle fh("test.txt", "w");
fh.write("Hello, World!");
// 离开作用域时自动关闭文件
}
catch (const exception& e) {
cout << "异常: " << e.what() << endl;
}
// 强保证示例
Stack s1, s2;
s1.push(1);
s1.push(2);
s2.push(3);
s1.swap(s2);
cout << "\ns1弹出: ";
while (!s1.empty()) {
cout << s1.pop() << " ";
}
cout << endl;
return 0;
}本章小结
本章学习了:
- 基本异常处理:try-catch-throw语句
- 标准异常类型:logic_error、runtime_error等
- 自定义异常:继承exception类
- 异常安全:RAII、强保证、noexcept
下一章,我们将学习文件操作,了解C++的文件读写操作。
