C++异常处理

垃圾回收算法

参考:C/C++中几种经典的垃圾回收算法

构造和析构中的异常抛出

1.1 抛出异常即检测是否产生异常,在C++中,其采用throw语句来实现,如果检测到产生异常,则抛出异常。

该语句的格式为: throw 表达式;

如果在try语句块的程序段中(包括在其中调用的函数)发现了异常,且抛弃了该异常,则这个异常就可以被try语句块后的某个catch语句所捕获并处理,捕获和处理的条件是被抛弃的异常的类型与catch语句的异常类型相匹配。由于C++使用数据类型来区分不同的异常,因此在判断异常时,throw语句中的表达式的值就没有实际意义,而表达式的类型就特别重要。

1.2 抛出异常实际是作为另一种返回值来使用的。 抛出异常的好处一是可以不干扰正常的返回值,另一个是调用者必须处理异常,而不像以前c语言返回一个整数型的错误码,调用者往往将它忽略了。

  1. 构造函数可以抛出异常。

  2. C++标准指明析构函数不能、也不应该抛出异常,析构函数已经变成了异常处理的一部分
    1)如果析构函数抛出异常,则异常点之后的程序不会执行,如果析构函数在异常点之后执行了某些必要的动作比如释放某些资源,则这些动作不会执行,会造成诸如资源泄漏的问题。

2)通常异常发生时,c++的机制会调用已经构造对象的析构函数来释放资源,此时若析构函数本身也抛出异常,则前一个异常尚未处理,又有新的异常,会造成程序崩溃的问题。
异常完全封装在析构函数内部,决不让异常抛出函数之外,来解决析构函数异常的问题。

~ClassName()
{
  try{
      do_something();
  }
  catch(){  //这里可以什么都不做,只是保证catch块的程序抛出的异常不会被扔出析构函数之外。

   }
}

参考:构造函数、析构函数抛出异常的问题

C++类体系中异常处理

1、在C++程序中,大部分的异常处理都是应用于自定义类类型。
通常情况下定义处理异常的类
然后再创建一个专门用于描述对应异常错误的对象实例
最后在应用程序中利用这个异常类对象实例处理应用的代码中可能发生的异常错误

#include <iostream>
#include <string>
using namespace std;

//自定义异常类
class MyException
{
public:
    MyException()                                                
    {
        m_context= "";                        
    }   
    ~MyException(){}
    MyException(const string & right)
    {
        m_context = right;                     
    }
    MyException(const char * right)
    {
        m_context = right;                     
    }
    string what() const  //获取异常信息的what方法成员
    {
        return m_context;                      
    }
private:
    string   m_context;                               
};

//自定义除法计算类
class Compute
{
public:
    Compute(int value1,int value2);
    ~Compute(){}                                           
    void divideCompute();                                 
private:
    int m_value1;                                                
    int m_value2;                                                
};

Compute::Compute(int value1,int value2)
{
    m_value1 = value1;
    m_value2 = value2;
}

void Compute::divideCompute()
{
    try
    {
        if(m_value2 == 0)
            throw MyException("value2 is 0!");
        else
            cout<<m_value1<<"/"<<m_value2<<" = "<<m_value1/m_value2<<endl;
    }   
    catch(MyException &e)   //数据类型来区分不同的异常
    {
        string errorMessage = e.what();   //获取对应异常信息
        cout<<errorMessage<<endl;        
    }
    catch(...)
    {
        cout<<"don't no error"<<endl;
    }
}

int main()
{
    int value1,value2;                             
    cout<<"Pleaseinput two value:"<<endl;          
    cin>>value1>>value2;      

    Compute compute(value1,value2);                
    compute.divideCompute();  

    return 0;   
}

2、异常类的继承处理
异常机制在继承体系中依然可以很好的运用。最重要的是利用类继承体系与对应的虚拟方法实现异常的多态性。通过自定义异常类派生新的异常类,除了包含基类基本异常处理方法,还可以包含自定义的异常处理方式。下面将会在上述实例中添加异常派生类。新的异常派生类不仅仅可以在异常处抛出对应的错误信息,还可以支持错误代码及对应的信息。

//自定义异常类
class MyException
{
public:
    virtual ~MyException(){}
    virtual string what() const  //获取异常信息的what方法成员
    {
        return m_context;                      
    }
//private:
protected:
    string   m_context;                               
};
//异常派生类,加入错误代码处理
class code_MyException : public MyException
{
protected:
    int  m_errorCode;       //错误代码
    string  m_errorCodeMsg; //错误信息  
public:
    code_MyException(int error_code, string error_code_msg = "", string context = "")
    {
        m_errorCode = error_code;                                                           
        m_errorCodeMsg = error_code_msg;                                                    
        m_context = context;                                                                
    }
    string what() const                                                                   
    {
        char tmp[20];                                                                       
        sprintf(tmp,"%d", m_errorCode);                                                     
        return string(tmp) + "," + m_errorCodeMsg + "," + m_context;
    }
    int getErrorCode() const                                                           
    {
        return m_errorCode;
    }
    string getErrorCodeMsg() const                                                   
    {
        return m_errorCodeMsg;
    }   
};
void Compute::divideCompute()
{
    try
    {
        if(m_value2 == 0)
            //throw MyException("value2 is 0!");
            throw code_MyException(10,"code msg:value2 is 0!","22value2 is 0!");
        else
            cout<<m_value1<<"/"<<m_value2<<" = "<<m_value1/m_value2<<endl;
    }   
    catch(MyException &e)   //数据类型来区分不同的异常
    {
        string errorMessage = e.what();   //获取对应异常信息
        cout<<errorMessage<<endl;        
    }
    catch(...)
    {
        cout<<"don't no error"<<endl;
    }
}

标准库提供异常处理类

C++标准库同样对异常作出了封装实现。标准库中异常实现也采用类继承层次式的结构。库中针对异常处理提供了一个层次化的类结构。该类层次中顶层基类为exception,即针对其它不同情况下的异常处理类都派生自exception类。
针对异常处理,总共提供了八个标准异常处理。
其中,四个针对语言级提供的抛出异常,分别为bad_alloc、bad_cast、bad_typeid以及bad_exception;
另外四个为C++标准库抛出的异常,分别是out_of_range、invalid_argument、overflow_error以及ios_base::failure。
下面将会针对这八类抛出异常情况作详细的讲述,分别说明每类异常表达的意义及基本用法。

1. bad_alloc new分配失败

bad_alloc针对C++中动态存储分配new的操作提供的异常信号,主要针对分配内存空间时内存耗尽(分配不足)时抛出的异常。这种异常的抛出有利于开发者在实际应用中针对new操作分配内存时提供某种分配出错的处理方式。下面可以通过一个基本小代码片段来理解bad_alloc异常处理情况。
void newChar()
{
     try
     {
         new char[10000000000000];     //通过new开辟一个超大的内存空间
     }catch(bad_alloc)
     {
         cout<<”memoryerror!”<<endl;
     }
}

上述代码动态new了一个很大的内容空间,当本地计算机内存不足时会默认抛出bad_alloc异常。随后catch捕捉到该异常后进入对应的异常处理块中。

2.bad_cast 【dynamic _cast

3. bad_typeid

bad_typeid是针对dynamic_cast操作空指针抛出的异常。

4. bad_exception

当应用程序出现了无法catch捕获的异常情况时,通常会调用terminate终止程序。而使用bad_exception时,出现类似情况则会抛出bad_exception异常,用来替代终止程序。bad_exception异常处理则主要针对应用提出的。这些类同样从exception类派生而来。

5.out_of_range

表示操作数组等结构下标时,访问超过设定范围所抛出的异常。它主要针对容器中at()方法与重载的下标访问运算符两类方法。

6.invalid_argument 传递无效参数

则表示向函数传递无效参数时抛出的异常,开发者可以针对该类抛出的异常作出相应的处理。

7.overflow_error

表示运算时候发生的上溢情况抛出的异常。

8.ios_base::failure

则是针对输出输入流操作时抛出的异常。

标准库中异常处理的封装可以通过查阅相关标准文档,根据提供的相关处理接口在实际的应用程序中使用。实际的exception基类中除了基本的构造函数外,重载实现一些运算符操作。最重要的是其what接口的定义,该方法定义为虚拟方法供其派生类中改写增加更多的异常处理。

C++应用程序错误处理

#include <iostream>
#include <string>
#include <deque>
#include <cstring>

using namespace std;

const int ERRORMSG_LEN = 300;     //错误信息长度常量定义
//错误信息类
class ErrorInfo 
{
public:
    ErrorInfo(){}                                                                        
    ~ErrorInfo(){}                                                                      
    ErrorInfo(const ErrorInfo& errorinfo);      //错误信息类拷贝构造
public:
    int m_errorNo;                                                                         
    char m_message[ERRORMSG_LEN+1];
};

ErrorInfo::ErrorInfo(const ErrorInfo& errorinfo)                             
{
    m_errorNo = errorinfo.m_errorNo;                                           
    strcpy(m_message,errorinfo.m_message);
}

 //错误消息容器类
class ErrorMessages                                                                                  
{
public:
    void setProgramInfo(const string& programInfoName);    
    string getProgramInfo();                               
    void insert(ErrorInfo &errInfo);                           
    bool get(ErrorInfo& errInfo);                              
    void clean();                                             
    bool isEmpty();                                          
    void insert(const int errorCode, const string& errorMessage);   
    void insert(const int errorCode, const char *errorMessage);     
private:
    string m_programInfoName;                                        
    deque<ErrorInfo> m_errorInfoQueue;                               
};

void ErrorMessages::setProgramInfo(const string& programInfoName)
{
    m_programInfoName= programInfoName;                              
}
string ErrorMessages::getProgramInfo()                               
{
    return m_programInfoName;                                        
}
void ErrorMessages::insert(ErrorInfo & errorinfo)                    
{
    m_errorInfoQueue.push_back(errorinfo);                                             
}
void ErrorMessages::insert(const int errorCode,const string& errorMessage)
{
    ErrorInfo errorinfo;                                                    
    errorinfo.m_errorNo= errorCode;  

    if(errorMessage.length() <= ERRORMSG_LEN)                         
        strcpy(errorinfo.m_message,errorMessage.c_str());                
    else                                                                   
    {
        strncpy(errorinfo.m_message,errorMessage.c_str(), ERRORMSG_LEN);
        errorinfo.m_message[ERRORMSG_LEN]= 0;
    }

    insert(errorinfo);                                                      
}
void ErrorMessages::insert(const int errorCode,const char *errorMessage)
{
    ErrorInfo errorinfo;  

    errorinfo.m_errorNo= errorCode;                                         
    if(strlen(errorMessage) <= ERRORMSG_LEN)
        strcpy(errorinfo.m_message,errorMessage);
    else
    {
        strncpy(errorinfo.m_message,errorMessage, ERRORMSG_LEN);
        errorinfo.m_message[ERRORMSG_LEN]= 0;
    }

    insert(errorinfo);
}
bool ErrorMessages::get(ErrorInfo& errorinfo)                            
{
    if(m_errorInfoQueue.empty())                                         
       return false;

    errorinfo = m_errorInfoQueue.front();                                 
    m_errorInfoQueue.pop_front();     

    return true;
}
void ErrorMessages::clean()                                             
{
    m_errorInfoQueue.clear();                                            
}
bool ErrorMessages::isEmpty()                                          
{
    return m_errorInfoQueue.empty();                                      
}

ErrorMessages g_errorMessages;                  //定义错误消息容器类对象
const int E_DIVISOR_ZERO = 200;                 //定义除数为0的错误代码常量
const string E_DIVISOR_ERROR = "divisor is0!";  //定义除数为0的错误信息常量

void divideCompute(int value1,int value2)                
{
    if(value2 == 0)                                             
    {
        g_errorMessages.insert(E_DIVISOR_ZERO,E_DIVISOR_ERROR);
    }
    else                                                       
    {
        cout<<"value1/value2:"<<(value1/value2)<<endl;
    }
}
int main(int argc,char *argv[])
{
    string name;                                                 
    ErrorInfo errorInfo;     

    name = argv[0];                                              
    g_errorMessages.setProgramInfo(name);                        
    cout<<"Programname:"<<g_errorMessages.getProgramInfo()<<endl;

    int value1,value2;                                           
    cout<<"Pleaseinput two value:"<<endl;                        
    cin>>value1>>value2;  

    divideCompute(value1,value2);                                
    g_errorMessages.get(errorInfo);  

    cout<<"errorcode:"<<errorInfo.m_errorNo<<" "
       <<"errormessage:"<<errorInfo.m_message<<endl;

    return 0;
}

参考:C++异常以及错误处理

#include <iostream>
#include <string>
using namespace std;

int main()
{
    try
    {
        int value1,value2;                                             
        cout<<"Pleaseinput two value:"<<endl;                          
        cin>>value1>>value2;                                           
        cout<<"Maybeexception code:"<<endl;                            

        if(value2== 0)                                                 
        {
            throw 0;
        }
        else                                                           
        {
            cout<<"value1/value2:"<<(value1/value2)<<endl;
        }
    }catch(int i)           //捕捉参数为整型的异常
    {
       cout<<"divisoris 0!"<<endl;     //异常处理代码
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值