• 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语句块能够更好的提高代码的维护性。

  • 相关阅读:
    mysql启动错误
    maven环境变量配置
    记一次服务器Tomcat优化经历
    自动定时备份删除脚本
    Tomcat网页加载速度过慢的解决方法
    tomcat运行war包报错,找不到context-root文件
    maven下配置pom.xml
    [LeetCode]题解(python):116-Populating Next Right Pointers in Each Node
    [LeetCode]题解(python):115-Distinct Subsequences
    [LeetCode]题解(python):114-Flatten Binary Tree to Linked List
  • 原文地址:https://www.cnblogs.com/free-1122/p/11336318.html
Copyright © 2020-2023  润新知