【C++笔记】十五、异常处理

1.返回错误码与abort函数

#include <iostream>
using namespace std;

int factorial(int n)  // 计算阶乘
{
    if(n < 0)
    {
        cout << "n不能小于0" << endl;
        abort();
       // return -1;  // 返回错误码
    }
    if(n == 0)
    {
        return 1;
    }
    else
    {
        return n * factorial(n - 1);
    }
}
int main(int argc, const char * argv[]) {
    // 返回错误码和abort函数
    // 返回错误码和abort的不足:
    // 1. 当异常条件非常多时,可能无法枚举所有的异常条件,或者遗忘部分的异常条件
    // 2. 对函数或方法返回的错误码没有进行判断,可能会造成严重的后果
    int n = -10;
    int result = factorial(n);
    if(result > 0)  // 对函数或方法返回的错误码进行判断
    {
        cout << "n! = " << result << endl;
    }
    else if(result == -1)  // 对函数或方法返回的错误码进行判断
    {
        cout << "n不能小于0" << endl;
    }
    return 0;
}

2.引发异常与捕捉异常(throw,try...catch)

#include <iostream>
using namespace std;

int factorial(int n)
{
    if(n < 0)
    {
        throw string("n不能小于0"); // 作用类似goto,会跳到catch里进行处理,
        //同时将throw后面的值作为参数传给catch
    }
    if(n == 0)
    {
        return 1;
    }
    else
    {
        return n * factorial(n - 1);
    }
}

void process()
{
    try {
        int n = -10;
        int jc = factorial(n);
        cout << n << "! = " << jc << endl;        
    }
    //catch (const char* s)
    catch(string s) 
    {
        cout << s << endl;
    }
}

int main(int argc, const char * argv[]) {
    // 引发异常与捕捉异常(throw、try...catch)
    
    //  1.  引发异常 throw
    //  2.  将可能产生异常的代码用try...catch括起来
    //  3.  在catch中处理异常
    
    //  优点:不需要对factorial的返回值进行判断,如果有异常发生,直接通过throw跳到异常处理的程序段
    process();
    return 0;
}

3.将对象作为异常表达式抛出

#include <iostream>
using namespace std;

class ExceptionClass1
{
public:
    int code;
    string msg;
};

class ExceptionClass2
{
public:
    float value;
    string msg;
};

void exceptionFunction()
{
    int n = 0;
    if(n < 0)
    {
        ExceptionClass1 ec1;
        ec1.code = n;
        ec1.msg = "n不能小于0";
        throw ec1;
    }
    else if(n == 0)
    {
        ExceptionClass2 ec2;
        ec2.value = 100.5;
        ec2.msg = "n不能等于0";
        throw ec2;
    }
    else
    {
        cout << "n = " << n << endl;
    }
    
}
int main(int argc, const char * argv[]) {
    // 将对象作为异常表达式抛出
    
    try
    {
        exceptionFunction();
    }
    catch(ExceptionClass1 &ec1)
    {
        cout << "ec1.code = " << ec1.code << endl;
        cout << ec1.msg << endl;
    }
    catch(ExceptionClass2 &ec2)
    {
        cout << "ec2.value = " << ec2.value << endl;  // 100.5
        cout << ec2.msg << endl;  // n不能等于0
    }
    return 0;
}

4.异常捕捉的else

#include <iostream>
using namespace std;

class ExceptionClass
{
public:
    float value;
    string msg;
    string exceptionClass;
};

class ExceptionClass1 : public ExceptionClass {
public:
    int code;
};

class ExceptionClass2 : public ExceptionClass
{

};

class ExceptionClass3 : public ExceptionClass
{

};
void exceptionFunction()
{
    int n = 0;
    if(n < 0)
    {
        ExceptionClass1 ec1;
        ec1.code = n;
        ec1.msg = "n不能小于0";
        ec1.exceptionClass = "ExceptionClass1";
        throw ec1;
    }
    else if(n == 0)
    {
        ExceptionClass2 ec2;
        ec2.value = 100.5;
        ec2.msg = "n不能等于0";
        ec2.exceptionClass = "ExceptionClass2";
        throw ec2;
    }
    
    else  
    {
        ExceptionClass3 ec3;
        ec3.value = 200.76;
        ec3.msg = "n不能大于0";
        ec3.exceptionClass = "ExceptionClass3";
        throw ec3;
    }
    
}
int main(int argc, const char * argv[]) {
    // 异常捕捉的else

        
    try
    {
        exceptionFunction();
    }
    
   /* 
   这里对每个异常都使用catch捕捉一次,当部分异常的处理方式是一样的时候
   这样处理就显得很浪费时间/臃肿
   	  catch(ExceptionClass1 &ec1)
    { 
        cout << "ec1.code = " << ec1.code << endl;
        cout << ec1.msg << endl;
    }*/
    /*catch(ExceptionClass2 &ec2)
    {
        cout << "ec2.value = " << ec2.value << endl;
        cout << ec2.msg << endl;
    }
    catch(ExceptionClass3 &ec3) //
    {
        cout << "ec3.value = " << ec3.value << endl;
        cout << ec3.msg << endl;
    }*/
    
    catch(ExceptionClass &ec)
    {
        if("ExceptionClass1" == ec.exceptionClass) // 通过使用if语句对异常进行判断执行相应的操作
        {
            ExceptionClass1 &ec1 = static_cast<ExceptionClass1&>(ec);
            cout << "ec1.code = " << ec1.code << endl;
            cout << ec1.msg << endl;
        }
        else  // 这里ExceptionClass2和ExceptionClass3的异常处理方式相同,所以用else代替,简洁了代码
        {
            cout << ec.exceptionClass << endl;
            cout << "ec.value = " << ec.value << endl;
            cout << ec.msg << endl;
        }
    }
    return 0;
}

5.异常类的基类:exception

#include <iostream>
using namespace std;

// std命名空间为用户设计好了一个异常类的基类:exception
class ExceptionClass1 : public exception  // private,protected都不可以
{
    
};
class ExceptionClass2 : public exception
{
    
};
int main(int argc, const char * argv[]) {
    //  异常类的基类:exception
    try
    {
        throw ExceptionClass2();
    }
    catch(ExceptionClass1 &ec1)  // 子类ExceptionClass1的引用
    {
        cout << "ExceptionClass1" << endl;
    }
    catch(exception &e)  // 基类exception的引用
    {
        cout << "exception" << endl;  // 打印 exception
    }
    return 0;
}

6.throw和noexcept

用throw关键字限制抛出异常的对象的类型,在C++11中不建议使用

#include <iostream>
using namespace std;

clss ExceptionClassA
{

};

clss ExceptionClassB
{

};

void process1() throw(ExceptionClassA,ExceptionClassB) // 在这里使用throw关键字,来限定抛出
// 的内容的类型应该是ExceptionClassA和ExceptionClassB这种的,即不允许抛出字符串形式的异常
{
    throw "出错了"; // 此处在运行时会报错,
}

int main( int argc, const char *argv[] ){
    try
    {
        process1();
    }
    catch(const char *s) 
    {
        cout << s << endl;
    }

    return 0;

}
#include <iostream>
using namespace std;

clss ExceptionClassA
{

};

clss ExceptionClassB
{

};

void process1() throw(ExceptionClassA,ExceptionClassB) 
{
    throw ExceptionClassA();
}

int main( int argc, const char *argv[] ){
    try
    {
        process1();
    }
    catch(const char *s) 
    {
        cout << s << endl;
    }
    catch(ExceptionClassA *a) 
    {
        cout << "ExceptionClassA" << endl;
    }

    return 0;

}

C++11中的 noexcept

#include <iostream>
using namespace std;

clss ExceptionClassA
{

};

clss ExceptionClassB
{

};

void process1() throw(ExceptionClassA,ExceptionClassB) 
{
    throw ExceptionClassA();
}

void process2() noexcept  // 表示函数process2()里面不能抛出任何异常
{
    throw "hello world";
}

void process3() noexcept(false) // 负负得正,允许抛出异常
{
    throw "hello world";
}

int main( int argc, const char *argv[] ){
    try
    {
        process1();
    }
    catch(const char *s) 
    {
        cout << s << endl;
    }
    catch(ExceptionClassA *a) 
    {
        cout << "ExceptionClassA" << endl;
    }

    return 0;

}
#include <iostream>
using namespace std;

clss ExceptionClassA
{

};

clss ExceptionClassB
{

};

void process1() throw(ExceptionClassA,ExceptionClassB) 
{
    throw ExceptionClassA();
}

template <class T>
void process2() noexcept(sizeof(T) < 4)  // T为char short时,不允许抛出异常,T为int、long
// 时,允许抛出异常
{
    throw "hello world";
}

template <class T>
void process3(int n) noexcept(sizeof(T) < 4 && n < 100) 
{
    throw "hello world";
}

int main( int argc, const char *argv[] ){
    try
    {
        process3<int>(100);  // 允许抛出异常
    }
    catch(const char *s) 
    {
        cout << s << endl;
    }
    catch(ExceptionClassA *a) 
    {
        cout << "ExceptionClassA" << endl;
    }

    return 0;
}

7.系统的预定义异常类

// 会按照套路/模板写即可,目前还没理解
#include <iostream>
#include <stdexcept>
using namespace std;

class MyException : public exception // exception的子类
{
private:
    const char *mWhat;
public:
    explicit MyException(const char *s)
    {
        mWhat = s;
    }
    virtual const char* what() const _NOEXCEPT
    {
        return mWhat;
    }
};

int main(int argc, const char * argv[]) {
    // 系统预定义的异常类
    // exception
    //    logic_error
    //    runtime_error
    
    int n = 30;
    try
    {
        if(n == 10)
        {
            throw length_error("长度错误");  // 隶属于logic_error
        }
        else if(n == 20)
        {
            throw out_of_range("超出范围"); // 隶属于logic_error
        }
        else if(n == 30)
        {
            throw MyException("MyException异常");
        }
    }
    catch(length_error &length)
    {
        cout << length.what() << endl;
    }
    catch(logic_error &logic)
    {
        cout << logic.what() << endl;
    }
    catch(exception &e)
    {
        cout << e.what() << endl; // MyException异常
    }
       
    return 0;
}

8.捕获由new产生的异常

#include <iostream>
#include <new>
using namespace std;
struct Big
{
    double array[3000000000000];
};

int main(int argc, const char * argv[]) {
    // 由new产生的异常,new分配空间过大,会产生bad_alloc错误
    Big *big;
    try
    {        
         big = new Big[10000]; // 这里是分配10000个array[3000000000000]大小的空间,如果不用try...catch,一定会抛出异常
    }
    catch (bad_alloc &ba)
    {
        cout << "下面是错误信息" << endl;
        cout << ba.what() << endl;  	 // 使用what方法返回错误信息
        exit(EXIT_FAILURE); 	         // 相当于 return 1;
    }
    delete [] big; // 如果电脑太好,有可能分配成功,这句话用来防止分配成功
    
    return 0;
}

9.阻止new抛出异常

#include <iostream>
#include <new>
using namespace std;
struct Big
{
    double array[3000000000000];
};

int main(int argc, const char * argv[]) {
    // 阻止new抛出异常
    Big *big;
    try
    {    // 在new后面加nothrow后,如果内存分配失败,不会抛出异常,而是会返回空指针给big    
        big = new(nothrow) Big[10000];  // nullptr
        if(big == nullptr)
        {
            cout << "分配内存空间失败." << endl;
            exit(EXIT_FAILURE);
        }
    }
    catch (bad_alloc &ba)   // 此处不会执行
    {
        cout << "下面是错误信息" << endl;
        cout << ba.what() << endl;
        exit(EXIT_FAILURE); // return 1;
    }
    delete [] big;
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

DUANDAUNNN

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

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

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

打赏作者

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

抵扣说明:

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

余额充值