C++ 异常处理:从入门到精通的 20 个实战技巧

目录

一、引言:程序世界的 "防暴警察"

二、异常处理的基础操作:从 try-catch 到 RAII

1. 异常处理的基本语法

2. 异常匹配的四大原则

 3. 资源管理的终极方案:RAII

三、自定义异常体系设计:打造专业级错误处理

4. 异常类的层次结构

5. 用户代码中的异常体系解析 

6. 异常处理的三大安全级别

四、多线程环境下的异常处理:从坑到填

7. 多线程异常的四大陷阱

8. 多线程异常处理的实战方案

 9. 用户代码中的多线程异常处理

五、性能优化:在优雅与效率间寻找平衡

10. 异常处理的性能开销

11. 性能优化的五大策略

六、与设计模式的结合:打造可维护的代码

12. 工厂模式创建异常

13. 策略模式处理异常

 14. 模板元编程处理异常

七、实战案例:服务器开发中的异常处理

15. 用户代码的异常体系分析

16. 异常处理的最佳实践

日志记录:

 重试机制:

异常隔离:

八、高级话题:从原理到优化

17. 异常处理的底层实现

18. 异常与其他语言的对比

19. 编译器优化与异常

 20.异常的黄金法则

异常练手代码


一、引言:程序世界的 "防暴警察"

想象一下,你正在驾驶一辆满载乘客的大巴车,突然遇到前方道路塌陷。如果没有刹车系统,大巴会直接冲进坑里;如果有刹车系统但没有安全带,乘客会在急刹车时受伤。C++ 异常处理机制就像是程序世界的 "刹车 + 安全带" 组合,让你在遇到意外时能够安全停车并保护资源。

在 C++ 中,异常处理是一把双刃剑:用得好可以写出健壮的代码,用得不好会导致程序崩溃或性能下降。本文将通过 20 个实战案例,带你从基础到高级全面掌握 C++ 异常处理的核心技术,包括:

  • 异常处理的底层原理
  • 自定义异常体系设计
  • 多线程环境下的异常处理
  • 性能优化策略
  • 与设计模式的结合
  • 实际项目中的最佳实践

二、异常处理的基础操作:从 try-catch 到 RAII

1. 异常处理的基本语法

try {
    // 可能抛出异常的代码
    if (y == 0) throw "除0错误";
} catch (const char* e) {
    // 处理异常
    cerr << "Error: " << e << endl;
}
  • throw:抛出异常对象(可以是任意类型)
  • try-catch:捕获并处理异常
  • 栈展开(Stack Unwinding):异常抛出后,自动调用栈中对象的析构函数

2. 异常匹配的四大原则

  1. 类型精确匹配catch(int) 只能捕获 int 类型异常
  2. 基类捕获派生类catch(Exception&) 可以捕获所有派生异常
  3. 数组和指针的特殊处理catch(int*) 无法捕获 int[5]
  4. 引用和值的区别catch(Exception) 会切割对象,丢失派生类信息

 3. 资源管理的终极方案:RAII

class File {
public:
    File(const string& path) { /* 打开文件 */ }
    ~File() { /* 关闭文件 */ }
};

void readFile() {
    File file("data.txt"); // 自动打开
    // 业务逻辑
} // 作用域结束自动关闭
  • RAII(Resource Acquisition Is Initialization):资源获取即初始化
  • 优势:自动管理资源,避免内存泄漏
  • 实战案例:用户代码中的div1函数存在内存泄漏,可改用 RAII:
void div1(int x, int y) {
    unique_ptr<int[]> p(new int[1024*1024*10]); // 自动释放
    if (y == 0) throw "除0错误";
    cout << x/(double)y << endl;
}

三、自定义异常体系设计:打造专业级错误处理

4. 异常类的层次结构

class Exception {
public:
    Exception(const string& msg) : _msg(msg) {}
    virtual string what() const { return _msg; }
protected:
    string _msg;
};

class SqlException : public Exception {
public:
    SqlException(const string& sql) : Exception("SQL Error"), _sql(sql) {}
    string what() const override { return _msg + " -> " + _sql; }
private:
    string _sql;
};
  • 设计原则
    1. 所有异常继承自基类Exception
    2. 提供what()方法返回错误信息
    3. 派生类包含特定错误数据

5. 用户代码中的异常体系解析 

class HttpServerException : public Exception {
public:
    HttpServerException(const string& type, const string& msg)
        : Exception(msg), _type(type) {}
    string what() const override {
        return "HttpServerException: " + _type + " -> " + _msg;
    }
private:
    string _type;
};
  • 优势
    1. 统一错误处理接口
    2. 支持多态捕获
    3. 方便扩展新异常类型

6. 异常处理的三大安全级别

  1. 基本保证(Basic Guarantee):对象处于有效状态,无资源泄漏
  2. 强保证(Strong Guarantee):操作要么成功,要么回滚
  3. 无抛出保证(No-throw Guarantee):函数绝对不会抛出异常

四、多线程环境下的异常处理:从坑到填

7. 多线程异常的四大陷阱

  1. 异常无法跨线程传播:子线程抛出的异常无法被主线程捕获
  2. 资源竞争:多个线程同时访问共享资源
  3. 线程局部存储(TLS):每个线程独立的异常存储
  4. 异常与信号的冲突:信号可能中断异常处理流程

8. 多线程异常处理的实战方案

#include <future>

void worker() {
    try {
        // 业务逻辑
        throw runtime_error("Worker error");
    } catch (...) {
        // 保存异常到线程局部存储
        thread_local exception_ptr error = current_exception();
    }
}

int main() {
    thread t(worker);
    t.join();
    
    // 检查线程局部存储中的异常
    if (thread_local_error) {
        try {
            rethrow_exception(thread_local_error);
        } catch (const exception& e) {
            cerr << "Caught: " << e.what() << endl;
        }
    }
    return 0;
}
  • 关键技术
    1. std::future 和 std::promise 传递异常
    2. 线程局部存储(thread_local
    3. std::exception_ptr 保存异常信息

 9. 用户代码中的多线程异常处理

int main() {
    while (1) {
        this_thread::sleep_for(chrono::seconds(1));
        try {
            HttpServer();
        } catch (const Exception& e) {
            cout << e.what() << endl;
        } catch (...) {
            cout << "Unknown Exception" << endl;
        }
    }
}
  • 分析
    1. 主线程循环处理异常
    2. 使用this_thread::sleep_for模拟服务器运行
    3. 捕获基类异常和未知异常

五、性能优化:在优雅与效率间寻找平衡

10. 异常处理的性能开销

操作开销(相对于无异常)
抛出异常10-100 倍
栈展开5-50 倍
类型匹配1-10 倍
构造异常对象1-5 倍

11. 性能优化的五大策略

  1. 避免不必要的异常

// 反模式:用异常处理常规错误
int divide(int a, int b) {
    if (b == 0) throw runtime_error("Divide by zero");
    return a / b;
}

// 优化:返回错误码
pair<int, bool> divide(int a, int b) {
    if (b == 0) return {0, false};
    return {a / b, true};
}

2. 使用 noexcept 声明

void sort(vector<int>& v) noexcept {
    // 保证不抛出异常
}

3. 轻量级异常类

class LightException {
public:
    LightException(const string& msg) : _msg(msg) {}
    // 避免复杂的析构函数
private:
    string _msg;
};

4.延迟异常处理

void process() {
    try {
        // 业务逻辑
    } catch (...) {
        // 记录日志,不立即处理
        log_error("Exception occurred");
        throw; // 重新抛出
    }
}

5.异常对象重用

const runtime_error divide_by_zero("Divide by zero");

void divide(int a, int b) {
    if (b == 0) throw divide_by_zero;
}

六、与设计模式的结合:打造可维护的代码

12. 工厂模式创建异常

class ExceptionFactory {
public:
    static unique_ptr<Exception> createException(const string& type) {
        if (type == "sql") {
            return make_unique<SqlException>("select * from users");
        } else if (type == "http") {
            return make_unique<HttpServerException>("get", "Not Found");
        }
        return nullptr;
    }
};

13. 策略模式处理异常

class ExceptionHandler {
public:
    virtual void handle(const Exception& e) = 0;
};

class LogHandler : public ExceptionHandler {
public:
    void handle(const Exception& e) override {
        cout << "Log: " << e.what() << endl;
    }
};

class EmailHandler : public ExceptionHandler {
public:
    void handle(const Exception& e) override {
        send_email("admin@example.com", e.what());
    }
};

 14. 模板元编程处理异常

template<typename T>
void process() {
    try {
        T::do_something();
    } catch (const exception& e) {
        // 处理T类型的异常
    }
}

七、实战案例:服务器开发中的异常处理

15. 用户代码的异常体系分析

void HttpServer() {
    srand(time(0));
    if (rand() % 3 == 0) {
        throw HttpServerException("get", "Not Found");
    } else if (rand() % 4 == 0) {
        throw HttpServerException("post", "Unauthorized");
    }
    CacheMgr();
}
  • 设计亮点
    1. 模拟真实服务器的异常场景
    2. 异常类型覆盖不同业务模块
    3. 多层调用链中的异常传播

16. 异常处理的最佳实践

日志记录
catch (const Exception& e) {
    ofstream log("error.log", ios::app);
    log << e.what() << endl;
}
 重试机制
bool connect_server() {
    for (int i = 0; i < 3; ++i) {
        try {
            // 连接服务器
            return true;
        } catch (const NetworkException& e) {
            cerr << "Retry " << i+1 << ": " << e.what() << endl;
            this_thread::sleep_for(chrono::seconds(1));
        }
    }
    throw runtime_error("Failed to connect");
}
异常隔离
void process_request() {
    try {
        // 处理请求
    } catch (...) {
        // 隔离异常,避免影响其他请求
        reset_request_state();
    }
}

八、高级话题:从原理到优化

17. 异常处理的底层实现

  1. 异常对象的创建

    • 栈上对象:直接复制
    • 堆上对象:需手动管理
  2. 栈展开过程
void func3() { throw 42; }
void func2() { func3(); }
void func1() { func2(); }

int main() {
    try {
        func1();
    } catch (int e) {
        cout << "Caught: " << e << endl;
    }
}
  1. 栈展开顺序:func3 () → func2 () → func1 () → main ()
  2. 异常与 RTTI

    • dynamic_cast 和 typeid 在异常处理中的应用
    • 性能开销:RTTI 会增加可执行文件大小

18. 异常与其他语言的对比

语言异常类型检查资源管理性能开销
C++运行时检查RAII
Java编译时检查自动垃圾回收
Python运行时检查自动垃圾回收

19. 编译器优化与异常

  1. -fno-exceptions:禁用异常处理
  2. -fno-unwind-tables:减少栈展开信息
  3. -O3:优化异常处理代码

 20.异常的黄金法则

最后,记住异常处理的黄金法则:

  1. 异常用于处理 "意外",而不是常规流程
  2. 资源管理优先使用 RAII
  3. 异常类型设计要层次分明
  4. 多线程环境下使用线程局部存储
  5. 性能敏感代码避免使用异常

异常练手代码

#include <bits/stdc++.h>
#include <thread>
using namespace std;

//struct AA
//{
//	AA()
//	{
//		cout << "AA" << endl;
//	}
//	~AA()
//	{
//		cout << "~AA" << endl;
//	}
//};
//
//void div1(int x, int y)
//{
//	int* p = new int[1024 * 1024 * 10];
//	if (y == 0)
//	{
//		throw "除0错误";
//	}
//	else
//	{
//		cout << x / (double)y << endl;
//		delete[] p;
//		cout << "delete[]" << endl;
//	}
//}
//
//int main()
//{
//	int x = 0, y = 0;
//	cin >> x >> y;
//	try
//	{
//		div1(x, y);
//	}
//	catch (const char* str)
//	{
//		cout << str << endl;
//	}
//	return 0;
//}

//double Division(int a, int b)
//{
//	// 当b == 0时抛出异常
//	if (b == 0)
//	{
//		throw "Division by zero condition!";
//	}
//	return (double)a / (double)b;
//}
//void Func()
//{
//	int* array = new int[10];
//	try 
//	{
//		int len, time;
//		cin >> len >> time;
//		cout << Division(len, time) << endl;
//	}
//	catch (...)
//	{
//		cout << "delete []" << array << endl;
//		delete[] array;
//		throw;
//	}
//	// ...
//	cout << "delete []" << array << endl;
//	delete[] array;
//}
//int main()
//{
//	try
//	{
//		Func();
//	}
//	catch (const char* errmsg)
//	{
//		cout << errmsg << endl;
//	}
//	return 0;
//}

// 服务器开发中通常使用的异常继承体系
// 定义了一个异常基类
class Exception
{
public:
	Exception(const string& errmsg, int id)
		:_errmsg(errmsg)
		, _id(id)
	{}
	// 可以在外部显示的查看错误信息是什么
	virtual string what() const
	{
		return _errmsg;
	}
protected:
	// 通常包括有异常信息和抛出异常所对应的id号码
	string _errmsg;
	int _id;
};

// 由基类异常继承而来的:数据库异常
class SqlException : public Exception
{
public:
	SqlException(const string& errmsg, int id, const string& sql)
		:Exception(errmsg, id)
		, _sql(sql)
	{}
	// 对基类中的输出信息进行对应的改造,使得输出对应的错误信息
	virtual string what() const
	{
		string str = "SqlException:";
		str += _errmsg;
		str += "->";
		str += _sql;
		return str;
	}
private:
	// 在数据库异常中新增了和数据库有关的信息
	const string _sql;
};

// 缓存区异常
class CacheException : public Exception
{
public:
	CacheException(const string& errmsg, int id)
		:Exception(errmsg, id)
	{}
	virtual string what() const
	{
		string str = "CacheException:";
		str += _errmsg;
		return str;
	}
};

// web服务器异常
class HttpServerException : public Exception
{
public:
	HttpServerException(const string& errmsg, int id, const string& type)
		:Exception(errmsg, id)
		, _type(type)
	{}
	virtual string what() const
	{
		string str = "HttpServerException:";
		str += _type;
		str += ":";
		str += _errmsg;
		return str;
	}
private:
	const string _type;
};

// 模拟数据库中的命令
void SQLMgr()
{
	srand(time(0));
	if (rand() % 7 == 0)
	{
		throw SqlException("权限不足", 100, "select * from name = '张三'");
	}
}

void CacheMgr()
{
	srand(time(0));
	if (rand() % 5 == 0)
	{
		throw CacheException("权限不足", 100);
	}
	else if (rand() % 6 == 0)
	{
		throw CacheException("数据不存在", 101);
	}
	SQLMgr();
}

void HttpServer()
{
	srand(time(0));
	if (rand() % 3 == 0)
	{
		throw HttpServerException("请求资源不存在", 100, "get");
	}
	else if (rand() % 4 == 0)
	{
		throw HttpServerException("权限不足", 101, "post");
	}
	CacheMgr();
}

int main()
{
	while (1)
	{
		this_thread::sleep_for(chrono::seconds(1));
		try
		{
			HttpServer();
		}
		catch (const Exception& e)
		{
			cout << e.what() << endl;
		}
		catch (...)
		{
			cout << "Unkown Exception" << endl;
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈大大陈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值