第26课 - 异常处理 - 下

第26课 - 异常处理 - 下

    一.深入异常处理

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

                   

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

            ...作参数表示可变参数函数,可以接受任意参数
      
 Source Example 1.1:
            #include <iostream>

            /* run this program using the console pauser or add your own getch, system("pause") or input loop */

            using namespace std;

            int test(int i)
            {
                if(i == 1)
                {
                    throw -1;
                }
                
                if (i == 2)
                {
                    throw "Error";
                }
                
                if (i == 3)
                {
                    throw 0.5;
                }
                    
                return i;
            }

            int main(int argc, char** argv) {
                
                for (int i = 0; i < 5; i++)
                {
                    try {
                        cout<<test(i)<<endl;
                    }    
                    /* 如果还要处理其他异常,可变参数的处理需要放到最后,否则编译不过! */
                    catch (...)
                    {
                        cout<<"Error Occur:"<<endl;
                    }
                
                }
                
                return 0;
            }
        输出结果如下:
           

        小总结:

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

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

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

           

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

        
    #include <iostream>

            /* run this program using the console pauser or add your own getch, system("pause") or input loop */

            using namespace std;

            int test(int i)
            {
                if((i >= 6) && (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<<"Error No:"<<e<<endl;
                            throw e;
                        }
                    }
                }
                catch(int e)
                {
                    /* 执行完该异常处理后向后执行,退出程序,并不会继续循环 */
                    cout<<"Exception No:"<<e<<endl;
                }
                
                return 0;
            }

            输出结果如下:


            

        1.3 在catch(...)语句块中,可以使用不带参数的throw语句抛出捕获的异常

     
   Source Example 1.3:
            #include <iostream>

            /* run this program using the console pauser or add your own getch, system("pause") or input loop */

            using namespace std;

            int test(int i)
            {
                if((i >= 6) && (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<<"Error"<<endl;
                            throw ;
                        }
                    }
                }
                catch(int e)
                {
                    /* 执行完该异常处理后向后执行,退出程序,并不会继续循环 */
                    cout<<"Exception No:"<<e<<endl;
                }
                
                return 0;
            }
        输出结果如下:
            
            

    二.异常与对象

        2.1 不要在构造函数中抛出异常

            2.1.1 在构造函数中可能申请系统资源,而在构造函数中出现异常会导致对象构造不完全

            2.1.2 不完全对象的析构是不会被调用的,因此会造成资源泄露

      
 Source Example 2.1:
            #include <iostream>

            /* run this program using the console pauser or add your own getch, system("pause") or input loop */

            using namespace std;


            class Test  {
            protected:
                int *p;
            public:
                Test()
                {
                    cout <<"Test()"<<endl;
                    p = new int[5];
                    
                    throw 1;
                }
                
                /* 在构造函数中抛出了异常,不会调用析构函数,内存泄露 */
                ~Test()
                {
                    cout<<"~Test()"<<endl;
                    delete[] p;
                }
            };
            
            int main(int argc, char** argv) {
                
                try
                {
                    Test t;        
                }
                catch(int error)
                {
                    cout<<"Error No:"<<error<<endl;
                }
                
                return 0;
            }

            输出结果如下:


    三.工程中的异常应用

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

        3.2 通过继承,可以得到一个异常家族

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

        3.4 由于对象构造和拷贝的开销,在定义catch语句块时用引用作为参数

        3.5 在工程中可以使用标准库中的异常类

        3.6 可将标准库中的异常类作为基类派生新的异常类

        3.7 标准库中的异常都是exception类派生的

        3.8 exception类主要有两个分支

            3.8.1 logic_error用于描述程序中出现的逻辑错误

                    如:传递无效参数

            3.8.2 runtime_error用于描述无法预料的事件造成的错误

                    如:内存耗尽,硬件错误

            3.8.3 logic_error和runtime_error都提供了一个参数为字符串的构造函数,这样就可以保持错误信息

            3.8.4 通过what()成员函数就可以得到异常信息

            
     
   Source Example 3.8:
            #include <iostream>
            #include <stdexcept>

            /* run this program using the console pauser or add your own getch, system("pause") or input loop */

            using namespace std;

            double Div(double a, double b)
            {
                if ((-0.0000001 < b)&&(b < 0.0000001))
                {
                    throw invalid_argument("Div by zero error...");
                }
            }

            
            int main(int argc, char** argv) {
                
                try
                {
                    cout<<Div(1,0)<<endl;
                }
                    /* 引用不需要拷贝构造 */
                catch(logic_error& e)
                {
                    cout<<e.what()<<endl;
                }
                
                return 0;
            }
        输出:
            Div by zero error...    
            
       
 Source Example:
            #include <iostream>
            #include <stdexcept>

            /* run this program using the console pauser or add your own getch, system("pause") or input loop */

            using namespace std;

            /* 自己定义异常类 */
            class DivZero : public logic_error{
            public:
                DivZero(const char *s) : logic_error(s)  
                {
                }
            };

            double Div(double a, double b)
            {
                if ((-0.0000001 < b)&&(b < 0.0000001))
                {
                    throw DivZero("Div by zero error...");
                }
            }

            
            int main(int argc, char** argv) {
                
                try
                {
                    cout<<Div(1,0)<<endl;
                }
                    /* 赋值兼容性原则 */
                catch(logic_error& e)
                {
                    cout<<e.what()<<endl;
                }
                
                return 0;
            }
            
        输出:
            Div by zero error...    

    四.函数级try用法

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

         
   int func(int i)                                        int func(int i)try        
            {                                                    {        
                try                                                    return i;
                {                              等价于            }
                    return i;               ------------>        catch(...)
                 }                          ------------>        {
                catch(...)                                            return -1;
                {                                                }
                    return -1;
                }
            }

        Source Example 4.1:
            #include <iostream>
            #include <stdexcept>

            /* run this program using the console pauser or add your own getch, system("pause") or input loop */

            using namespace std;

            int func(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<<func(i)<<endl;
                }
                
                return 0;
            }
        输出: -1 1 2 3 4         

    五.小结

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

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

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

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

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

            
           

猜你喜欢

转载自blog.csdn.net/qq_36521904/article/details/80499087