cpp拾遗——异常
1. 简介
当程序某个函数出错,但处理错误的逻辑在另一个函数,则使用异常。
2. 异常格式
抛出异常
当发生异常时,使用 throw 抛出一个对象。对象是堆内存,所以可以跨函数访问。
void func() {
throw 表达式;
}
捕获异常
try {
需要保护的程序;
}
catch (类型 形参) {
处理异常的程序;
}
catch (...) {
当所有异常处理都不匹配,则使用通用处理程序;
}
3. 示例
#include <iostream>
#include <stdlib.h>
#include <assert.h>
using namespace std;
const int ARG_ERR = 100;
void func1(int a) {
if (a == 0) {
throw ARG_ERR;
}
throw 0;
}
void func() {
try {
func1(1);
}
catch (int e) {
if (e == ARG_ERR) {
cout << "收到传参错误" << endl;
exit (1);
}
cout << "收到未知异常,没能力处理,向上传递" << endl;
throw;
}
catch (...) {
cout << "收到未知异常,没能力处理,向上传递" << endl;
throw;
}
}
int main()
{
try {
func();
}
catch (...) {
cout << "收到未知异常" << endl;
}
return 0;
}
4. 异常匹配是严格进行类型匹配
throw 'c';
catch (int a) { // 接不到
}
- 栈解旋
当异常抛出后,函数返回,函数的栈对象被析构 - 异常接口声明
在声明函数时,可以显示指定该函数只能抛出的异常。
void func() throw(int , char *, int *); // 只能抛出这3种类型的异常
void func2() throw(); // 不能抛出任何异常
void func3(); 可以抛出任何异常
- 异常和对象生命周期
#include <iostream>
#include <stdlib.h>
#include <assert.h>
using namespace std;
class T {
public:
T() {
cout << "构造" << endl;
}
T (const T &t) {
cout << "拷贝构造" << endl;
}
~T () {
cout << "析构" << endl;
}
};
void func1(int a) {
throw T();
}
void func() {
try {
func1(0);
}
catch (T t) {
cout << "捕捉" << endl;
throw;
}
}
int main()
{
try {
func();
}
catch (T t) {
cout << "main 捕捉" << endl;
}
catch (...) {
cout << "收到未知异常" << endl;
}
return 0;
}
运行结果
构造 // 异常对象,异常对象基于堆内存
拷贝构造 // 构造捕获函数实参对象,基于栈内存
捕捉 // 执行捕获函数
析构 // 析构捕获函数实参
拷贝构造 // 构造main捕获函数实参对象,基于栈
main 捕捉
析构 // 析构捕获对象实参
析构 // 析构异常对象
若异常对象继续抛出,则不会被释放,会一直到异常不再抛出再析构
使用引用接异常对象
#include <iostream>
#include <stdlib.h>
#include <assert.h>
using namespace std;
class T {
public:
T() {
cout << "构造" << endl;
}
T (const T &t) {
cout << "拷贝构造" << endl;
}
~T () {
cout << "析构" << endl;
}
};
void func1(int a) {
throw T();
}
void func() {
try {
func1(0);
}
catch (T &t) {
cout << "捕捉" << endl;
throw;
}
}
int main()
{
try {
func();
}
catch (T &t) {
cout << "main 捕捉" << endl;
}
catch (...) {
cout << "收到未知异常" << endl;
}
return 0;
}
运行结果
构造
捕捉
main 捕捉
析构
不能使用指针接异常对象,因为要保证异常对象是基于堆的,不好实现。
- 异常和多态
利用多态特性,可以实现捕获框架不变,处理各种异常
#include <iostream>
#include <stdlib.h>
#include <assert.h>
using namespace std;
class T {
public:
virtual const char* info() = 0;
};
class mem_leak_c : public T {
public:
mem_leak_c() {
}
~mem_leak_c() {
}
const char * info() {
return "内存泄漏";
}
};
class float_c : public T {
public:
float_c() {
}
~float_c() {
}
const char *info() {
return "浮点数运算";
}
};
void func1(int a) {
if (a > 0) {
throw float_c();
}
else {
throw mem_leak_c();
}
}
void func() {
try {
func1(1);
}
catch (T &t) {
cout << "发生了 " << t.info() << " 异常" << endl;
throw;
}
}
int main()
{
try {
func();
}
catch (T &t) {
cout << "main 捕捉" << endl;
}
catch (...) {
cout << "收到未知异常" << endl;
}
return 0;
}
9. 标准库异常
示例:
#include "iostream"
using namespace std;
#include <stdexcept>
class Teacher
{
public:
Teacher(int age) //构造函数, 通过异常机制 处理错误
{
if (age > 100)
{
throw out_of_range("年龄太大");
}
this->age = age;
}
protected:
private:
int age;
};
void mainxx()
{
try
{
Teacher t1(102);
}
catch (out_of_range e)
{
cout << e.what() << endl;
}
exception e;
system("pause");
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?