C++--第26课 - 异常处理 - 下

Posted free-1122

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++--第26课 - 异常处理 - 下相关的知识,希望对你有一定的参考价值。

第26课 - 异常处理 - 下

1. 问题一

有时在工程中关心是否产生了异常,而不关心具体的异常类型,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)  //只能放在catch之前,否则成了死代码

          

            cout<<"Exception: "<<e<<endl;

       

        catch(...)

       

            cout<<"Exception Occur"<<endl;

       

   

    cout << "Press the enter key to continue ...";

    cin.get();

    return EXIT_SUCCESS;

运行结果:

0

Exceptin Occur

Exceptin Occur

Exceptin Occur

Exceptin:c

5

6

7

8

9

catch(...)可以捕获所有异常但却无法得到异常信息。

catch(...)一般作为最后一个异常处理块出现。

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

 

2. 问题二

在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

   

        for(int i=0; i<10; i++)

       

            try

           

                cout<<test(i)<<endl;

           

            catch(int e)

              

                cout<<"Exception: "<<e<<endl;

                throw e;   //有异常,终止了for循环

           

       

   

    catch(int e)

   

        cout<<"Catch: "<<e<<endl;

    

    cout << "Press the enter key to continue ...";

    cin.get();

    return EXIT_SUCCESS;

运行结果:

0

1

2

3

4

5

Exception:6

Catch:6

 

3. 问题三

在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;

           

       

   

    catch(int e)

   

        cout<<"Catch: "<<e<<endl;

   

    cout << "Press the enter key to continue ...";

    cin.get();

    return EXIT_SUCCESS;

运行结果:

0

1

2

3

4

5

Exception Occur

Catch:6

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

 

4. 问题4

不要在构造函数中抛出异常。在构造函数可能申请系统资源,而在构造函数中抛出异常会导致对象构造不完全。不完全对象的析构函数是不会被调用的,因此可能造成资源泄漏。语法上来说是合法的,但是会造成问题。

构造函数中的异常示例。

#include <cstdlib>

#include <iostream>

using namespace std;

class Test

    int* p;

public:

    Test()

   

        cout<<"Test()"<<endl;

        p = new int[5];

        throw 10; /*构造函数里面抛出异常,在这里没有被处理,去上一层main函数中 */

   

    ~Test()

   

        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;

运行结果:

Test()

Catch:10

 

5. 工程中的异常应用

在工程中会定义一系列的异常类。

通过继承,可以得到一个异常类族。

每个类代表工程中可能出现的一种异常类型。

由于对象构造与拷贝的开销,在定义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)

   

        cout<<e.what()<<endl;

   

    cout << "Press the enter key to continue ...";

    cin.get();

    return EXIT_SUCCESS;

运行结果:

Divide by zero...

 

6. 函数级try语法

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

int func(int i)

try

return i;

catch(...)

return -1;

等价于

int func(int i) try

return i;

catch(...)

return -1;

 

函数级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;

运行结果:

-1

1

2

3

4

 

小结:

catch(...)可以捕获所有异常。

catch(...)经常作为最后一个catch语句出现。

不要在构造函数中够抛出异常,这样可能造成资源泄露。

工程中经常以标准库中的异常类作为项目异常的基础。

函数级try语句块能够更好的提高代码的维护性。

 

以上是关于C++--第26课 - 异常处理 - 下的主要内容,如果未能解决你的问题,请参考以下文章

C++--第25课 - 异常处理 - 上

第08课:服务异常处理

使用AOP校验用户登录和异常处理-2020-10-26

Python基础语法介绍 - 面向对象(下)和异常处理

OD 第6课

SVN 异常处理(一)