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) { // 接不到

}
  1. 栈解旋
    当异常抛出后,函数返回,函数的栈对象被析构
  2. 异常接口声明
    在声明函数时,可以显示指定该函数只能抛出的异常。
void func() throw(int , char *, int *); // 只能抛出这3种类型的异常
void func2() throw(); // 不能抛出任何异常
void func3(); 可以抛出任何异常
  1. 异常和对象生命周期
#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 捕捉
析构

不能使用指针接异常对象,因为要保证异常对象是基于堆的,不好实现。

  1. 异常和多态
    利用多态特性,可以实现捕获框架不变,处理各种异常
#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");
}




posted on 2022-06-08 09:29  开心种树  阅读(94)  评论(0编辑  收藏  举报