• 【C/C++】异常



    在这里插入图片描述

    1.C++异常概念

    异常是一种处理错误的方式,当一个函数发现自己无法处理的错误时就库抛出异常,让函数的直接或者间接的调用者处理这个错误。

    关键字

    • throw:抛出异常。
    • catch:该关键字用于捕获异常,可以有多个catch进行捕获
    • try:try中的代码标识将被激活特点的异常

    如果有一个块抛出一个异常,捕获异常的方法会使用 try 和 catch 关键字。try 块中放置可能抛出异常的代码,try 块中的代码被称为保护代码。

    double Division(int a,int b)
    {
        if(b==0)	
            throw "Divison by zero";
        else
            return (double)a/(double)b;
    }
    void fun()
    {
        try
        {
            int len,time;
            cin>>len>>time;
            cout<<Division(len,time)<<endl;
        }//捕获并处理异常
        catch(const char*err_msg)
        {
            cout<<err_msg<<endl;
        }
    }
    int main()
    {
        try
        {
            fun();
        }
        catch(const char* err_msg)
        {
            cout<<err_msg<<endl;
        }
        return 0;
    }
    

    输入:5 0
    输出:Divison by zero

    在这里插入图片描述

    1.1 catch(…)捕获任意异常

    catch(…)可以捕获任意类型的异常,问题是不知道异常错误是什么。

    double Division(int a,int b)
    {
        if(b==0)	
            throw "Divison by zero";
        else if(a==0)
            throw a;
        else
            return (double)a/(double)b;
    }
    int main()
    {
        int a,b;
        cin>>a>>b;
        try
        {
            Division(a,b);
        }
        catch(const char*err_msg)
        {
            cout<<err_msg<<endl;
        }
        catch(...)
        {
            cout<<"未知异常:"<<endl;
        }
        return 0;
    
    

    输入:0 7

    输出:未知异常:

    2.异常抛出的匹配原则

    1.异常是通过抛出对象而引发的,该对象的类型决定了应该激活哪个catch的处理代码

    比如你抛出的是一个字符串,那么对应的异常捕获也是字符串类型;如果抛出的是一个int类型,那么异常捕获也是int类型。

    double Division(int a,int b)
    {
        if(b==0)	
            throw "Divison by zero";
        else
            return (double)a/(double)b;
    }
    int main()
    {
        int a,b;
        cin>>a>>b;
        try
        {
            Division(a,b);
        }
        catch(int err_id)
        {
            cout<<err_id<<endl;
        }
        catch(const char* err_msg)
        {
            cout<<err_msg<<endl;
        }
        return 0;
    }
    

    输入:7 0
    输出:Divison by zero

    1. 被选中的处理代码是调用链中与该对象类型匹配且离抛出异常位置最近的那一个 【就近原则】
    2. 抛出异常对象后,会生成一个异常对象的拷贝,因为抛出的异常对象可能是一个临时对象,所以会生成一个拷贝对象,这个拷贝的临时对象会在被catch以后销毁。
    3. 可以抛出的派生类对象,使用基类捕获;C++标准库的异常机制也是使用的这个方法

    **在函数调用链中异常栈展开匹配原则 **

    • 首先检查throw本身是否在try块内部,如果是再查找匹配的catch语句。如果有匹配的,则调到catch的地方进行处理。

    • 没有匹配的catch则退出当前函数栈,继续在调用函数的栈中进行查找匹配的catch。

    • 如果到达main函数的栈,依旧没有匹配的,则终止程序。

    • 找到匹配的catch子句并处理以后,会继续沿着catch子句后面继续执行。

    在这里插入图片描述

    2.1异常的重抛出

    有可能单个的catch不能完全处理一个异常,在进行一些校正处理以后,希望再交给更外层的调用链函数来处理,catch则可以通过重新抛出将异常传递给更上层的函数进行处理 。

    double Division(int a, int b)
    {
        if (b == 0)
            throw "Divison by zero";
        else
            return (double)a / (double)b;
    }
    void func()
    {
        int* arr = new int[4];
    	try
    	{
    		int a, b;
    		cin >> a >> b;
    		Division(a,b);
    	}
    	catch (...)
    	{
    		cout << "delete[]" << arr << endl;
    		delete[] arr;
    		throw;
    	}
    	cout << "delete[]" << arr << endl;
    	delete[] arr;
    }
    int main()
    {
    	try
    	{
    		func();
    	}
    	catch (const char* err_msg)
    	{
    		cout <<"err_mgs:" << err_msg << endl;
    	}
    }
    

    在这里插入图片描述

    2.2异常规范
    // 这里表示这个函数会抛出A/B/C/D中的某种类型的异常
    void fun() throw(A,B,C,D);
    // 这里表示这个函数只会抛出bad_alloc的异常
    void* operator new (std::size_t size) throw (std::bad_alloc);
    // 这里表示这个函数不会抛出异常
    void* operator new (std::size_t size, void* ptr) throw();
    
    //C++11新增的noexcept,表示不会抛异常
    thread() noexcept;	//执行thread()时候,不会抛异常
    thread(thread&&x) noexcept; 
    

    3.自定义异常体系

    在这里插入图片描述

    class Exception
    {
    public:
    	Exception(const string&errmsg, int id)
    		:_errmsg(errmsg),_id(id)
    	{}
    	//返回异常信息
    	virtual string what()const
    	{
    		return _errmsg;
    	}
    	int getid()
    	{
    		return _id;
    	}
    protected:
    	int _id;//错误码
    	string _errmsg;
    };
    //SQL语句错误
    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:
    	string _sql;
    };
    class CacheException :public Exception
    {
    public:
    	CacheException(const string& errmsg,int id)
    		: Exception(errmsg,id)
    	{}
    	virtual string what()const
    	{
    		string str = "CacheException err:";
    		str += _errmsg;
    		return str;
    	}
    };
    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 Sqlmsg()
    {
    	if (rand() < RAND_MAX / 4)
    	{
    		throw SqlException("权限不足", 1, "select * from student where name ='cxk'");
    	}
    	else
    	{
    		cout << "Sql sucess" << endl;
    	}
    }
    void Cachemsg()
    {
    	if (rand() < RAND_MAX / 8)
    	{
    		throw CacheException("权限不足", 2);
    	}
    	else if(rand()< RAND_MAX/4)
    	{
    		throw CacheException("数据不存在", 3);
    	}
    	else
    	{
    		cout << "Cache success" << endl;
    	}
    }
    void seedmsg(const string& str)
    {
    	if (rand() < RAND_MAX/10)
    	{
    		throw HttpServerException("SeedMsg::网络错误", 4, "put");
    	}
    	else if (rand() < RAND_MAX / 5)
    	{
    		throw HttpServerException("SeedMsg::你已经不是对方好友", 5, "post");
    	}
    	else
    	{
    		cout << "消息发送成功###->" << str << endl;
    	}
    }
    
    void HttpServer()
    {
    	if (rand() < RAND_MAX / 4)
    	{
    		throw HttpServerException("请求资源不存在", 404, "get");
    	}
    	else if (rand() < RAND_MAX / 4)
    	{
    		throw HttpServerException("权限不足", 501, "post");
    	}
    	else
    	{
    		cout << "Http success" << endl;
    	}
    	Cachemsg();
    }
    

    测试和实现的结果

    int main()
    {
    	srand(time(0));
    	while (1)
    	{
    		Sleep(2000);
    		try
    		{
    			//如果出现的是网络错误,那么就要反复发送,如果发送了10次也没有成功,那么就抛异常。
    			for (int i = 0;i < 10;i++)
    			{
    				try
    				{
    					
    					string s = "你好,一起去跳唱跳RAP吗?";
    					//如果成功了就直接退出
    					seedmsg(s);
    					break;
    				}
    				catch (const Exception& e)
    				{
    					if (e.getid() == 4)
    					{
    						continue;
    					}
    					else
    					{
    					//再次抛出异常
    						throw e;
    					}
    				}
    			}
    
    		}
    		catch (const Exception& e)
    		{
    			cout << e.what() << endl;
    		}
    		catch (...)
    		{
    			cout << "Unkown Exception" << endl;
    		}
    	}
    	return 0;
    }
    

    在这里插入图片描述

  • 相关阅读:
    zemax西德莫尔目镜
    Fourier分析入门——第11章——Fourier变换
    springboot 事务注解
    Taro小程序隐私协议开发指南填坑
    【深入浅出Spring6】第九期——Spring对事务的支持
    前端实现下载文件(处理后端返回的二进制流)
    vim编辑器使用
    typescript54-泛型约束
    【LUA】如何借助redis的lua功能实现库存扣减
    艺术表现形式
  • 原文地址:https://blog.csdn.net/qq_53893431/article/details/127070380