第26节 异常处理 – 下

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pt_raspi_fresher/article/details/88650923

-------------------------------------资源来源于网络,仅供自学使用,如有侵权,联系我必删.

第一:

深入异常处理

问题

有时在工程中只关心是否产生了异常 , 而不关心具体的异常类型 , C++ 语言可以做到吗 ?

 C++ 中的 catch 语句可以使用 … 捕获所有的异常

#include <cstdlib>
#include <iostream>

using namespace std;

int test(int i)
{
    if( i == 1 )
    {
        throw "p";
    }
    
    if( i == 2 )
    {
        throw 0.5;
    }
    
    if( i == 3 )
    {
        throw 3;
    }
    
    if( i == 4 )
    {
        throw 'c';
    }
    
    return i;
}

int main(int argc, char *argv[])
{
    for(int i=0; i<10; i++)
    {
        try
        {
            cout<<test(i)<<endl;
        }
        catch(char e)//字符信息
        {   
            cout<<"Exception: "<<e<<endl;
        }
        //一般作为最后一个异常处理块出现
        catch(...)//使用 … 捕获所有的异常
        {
            cout<<"Exception Occur"<<endl;
        }
    }
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

?  catch( …) 可以捕获所有异常但却无法得到异常信息
?  catch( …)一般作为最后一个异常处理块出现

看见代码中的 catch 就要意识到这里在处理异常情况 , 而异常是在对应的 try 中产生的

第二:

  在 catch 语句块中仍然可以抛出异常

#include <cstdlib>
#include <iostream>

using namespace std;

int test(int i)
{
    if( (6 <= i) && (i <= 9) )
    {
        throw i;//抛出异常
    }
    
    return i;
}

int main(int argc, char *argv[])
{
    try       //2
    {
        for(int i=0; i<10; i++)
        {
            try
            {
                cout<<test(i)<<endl;
            }
            catch(int e)
            {   
                cout<<"Exception: "<<e<<endl;
                
                //跑出的异常由外层try捕获 --> catch(int e) 捕获
                throw e;//1
            }
        }
    }
    catch(int e)//3
    {
        cout<<"Catch: "<<e<<endl;
    }
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

第三:

  在 catch( …) 语句块中 , 可以通过不带参数的 throw 语句抛出捕获的异常

#include <cstdlib>
#include <iostream>

using namespace std;

int test(int i)
{
    if( (6 <= i) && (i <= 9) )
    {
        throw i;
    }
    
    return i;
}

int main(int argc, char *argv[])
{
    try
    {
        for(int i=0; i<10; i++)
        {
            try
            {
                cout<<test(i)<<endl;
            }
            catch(...)
            {   
                cout<<"Exception Occur"<<endl;
                
                throw;//没有参数的throw
            }
        }
    }
    catch(int e)
    {
        cout<<"Catch: "<<e<<endl;
    }
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

第四:

异常与对象

? 不要构造函数抛出异常
?  在构造函数可能申请系统资源 , 而在构造函数中抛出异常会导致对象构造不完全
?  不完全对象的析构函数是不会被调用的 , 因此可能造成资源泄漏

构造函数中的异常示例

#include <cstdlib>
#include <iostream>

using namespace std;

class Test
{
    int* p;
public:
    Test()
    {
        cout<<"Test()"<<endl;
        
        p = new int[5];//申请5个整型数
        
        throw 10;
    }
    
    ~Test()//不会调用析构函数,20个字节资源泄漏
    {
        cout<<"~Test()"<<endl;
        delete[] p;
    }
};

int main(int argc, char *argv[])
{
    try
    {
        Test t;
    }
    catch(int e)
    {
        cout<<"Catch: "<<e<<endl;
    }
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

第五:

工程中的异常应用

?  在工程中会定义一系列的异常类
?  通过继承 , 可以得到一个异常类族
?  每个类代表工程中可能出现的一种异常类型
?  由于对象构造与拷贝的开销 , 在定义 catch 语句块时使用引用作为参数

?  在工程中可以使用标准库中的异常类
?  可将标准库中的异常类作为基类派生新的异常类
?  标准库中的异常都是从 exception 类派生的
? exception 类有两个主要的分支
    ? logic_error 用于描述程序中出现的逻辑错误
    ?  如 : 传递无效参数
? runtime_error 用于描述无法预料的事件所造成的错误
    ?  如 : 内存耗尽 , 硬件错误

标准库中的异常

? logic_error runtime_error 都提供了一个参数为字符串的构造函数 , 这样就可以保持错误信息
?  通过 what() 成员函数就可以得到错误的信息

异常的工程应用初探

#include <cstdlib>
#include <iostream>
#include <stdexcept>//标准库异常

using namespace std;

class divide_by_zero : public logic_error//继承定义新的异常类
{
public:
    divide_by_zero(const char* s) : logic_error(s)
    {
    }
};

double Div(double a, double b)
{
    if( (-0.00000001 < b) && ( b < 0.00000001) )
    {
        throw divide_by_zero("Divide by zero...");//抛出异常
    }
    
    return  a / b;
}

int main(int argc, char *argv[])
{
    try
    {
        cout<<Div(1, 0)<<endl;
    }
    catch(exception& e)//根信息exception 作为异常类捕获,可以捕获所有异常,异常信息
    {
        cout<<e.what()<<endl;//得到错误的信息
    }
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

第六:

函数级try 语法

可以将函数体作为一个完整的 try 语句块

#include <cstdlib>
#include <iostream>
#include <stdexcept>

using namespace std;

int func1(int i)
{
    try
    {
        if( i > 0 )
        {
            return i;
        }
        else
        {
            throw "error";
        }
    }
    catch(...)
    {
        return -1;
    }
}

int func2(int i) try
{
    if( i > 0 )
    {
        return i;
    }
    else
    {
        throw "error";
    }
}
catch(...)
{
    return -1;
}

int main(int argc, char *argv[])
{
    for(int i=0; i<5; i++)
    {
        cout<<func2(i)<<endl;
    }
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

函数级 try 语法可以更好将正常逻辑代码与异常处理代码分开 , 提高代码的可读性与维护性

小结:

?  catch( …) 可以捕获所有异常
?  catch( …) 经常作为最后一个 catch 语句出现
?  不要在构造函数中抛出异常 , 这样可能造成资源泄露
?  工程中经常以标准库中的异常类作为项目异常的基础
?  函数级 try语句块能够更好的提高代码的维护性

猜你喜欢

转载自blog.csdn.net/pt_raspi_fresher/article/details/88650923