zoukankan      html  css  js  c++  java
  • C++_异常5-异常规范和栈解退

    异常规范

    异常规范的理念看似有前途,但实际的使用效果并不好。

    忽视异常规范之前,您至少应该知道它是什么样的,如下所示:

    double harm(double a) throw(bad_thing);  //may throw bad_thing exception

    double harm(double a) throw();    //doesn't throw an exception

    其中throw()部分就是异常规范,它可能出现在函数原型和函数定义中,可包含类型列表,也可不包含。

    异常规范的另一个作用是,让编译器添加执行运行阶段检查的代码,检查是否违反了异常规范。

    这很难检查;

    marm()可能不会引发异常,但它可能调用一个函数,而这个函数调用的另一个函数引发了异常。

    另外,您给函数编写代码时它不会引发异常,但库更新后它却会引发异常。

    总之,编程社区达成的意见是不要使用这个功能。

    栈解退

     假设try块没有直接调用引发异常的函数B,而是调用了对引发异常的函数B进行调用的函数A,即A调用了B。

    则程序流程将从引发异常的函数B跳到包含try块和处理程序的函数。这涉及到栈解退。

    首先要了解C++是如何处理函数调用和返回的。C++通常通过将信息放到中来处理函数调用

    具体来说,程序将调用函数的指令地址(返回地址)放到栈中。

    当被调用的函数执行完毕后,程序将使用该地址来决定从哪里开始继续执行。

    另外函数调用将函数A参数放到栈中。在栈中这些函数参数被视为自动变量。

    如果被调用函数B创建了新的自动变量,则这些变量也将被添加到栈中。

    如果被调用函数B调用了另一个函数C,则函数C的信息也将被添加到栈中。以此类推;

    当函数C结束时,程序流程将跳到该函数C被调用时存储的地址(返回地址)处,同时栈顶的元素被释放。

    因此函数都通常返回到调用它的函数处,同时每个函数都在结束时释放器自动变量。

    如果自动变量是类对象,则类的析构函数(如果有的话)也将被调用。

    现在假设函数由于出现异常(而不是由于return)而终止,则程序也将释放栈中的内存。

    但不会在释放栈的第一个返回地址后停止,而是继续释放栈,直到找到一个位于try块中的返回地址。

    随后控制权将转移到位于try块尾的异常处理程序,而不是函数调用后面的第一条语句。

    这个过程就被称为栈解退

    和函数返回一样,对于栈中的自动类对象,类的析构函数将被调用。

    然而函数返回仅仅处理该函数放在栈中的对象。

    而throw语句则处理try块和throw之间整个函数调用序列放在栈中的对象。

    接下来上代码,看看栈解退的例子:

      1 //error5.cpp  -- unwinding the stack
      2 #include <iostream>
      3 #include <cmath>
      4 #include <string>
      5 #include "exc_mean.h"
      6 
      7 class demo
      8 {
      9 private:
     10     std::string word;
     11 
     12 public:
     13     demo(const std::string & str)
     14     {
     15         word = str;
     16         str::cout<<"demo "<<word<<" created
    ";
     17     }
     18 
     19     ~demo()
     20     {
     21         std::cout<<" demo "<<word<<" destroyed
    ";
     22     }
     23 
     24     void show() const
     25     {
     26         std::cout<<" demo "<<word<< " lives!
    ";
     27     }
     28 };
     29 
     30 
     31 //function prototypes
     32 double hmean(double a, double b);
     33 double gmean(double a, double b);
     34 double means(double a, double b);
     35 
     36 int main()
     37 {
     38     using std::cout;
     39     using std::cin;
     40     using std::end;
     41 
     42    double x,y,z;
     43    {
     44         demo d1("found in block in main()");
     45         cout<<"Enter two numbers:";
     46         while(cin>>x>>y)
     47         {
     48             try{
     49                 z =means(x,y);
     50                 cout<<"The mean mean of"<<x<<" and "<<y
     51                        <<" is "<<z<<endl;
     52                 cout<<"Enter next pair:";
     53             }
     54             catch(bad_hmean & bg)
     55             {
     56                 bg.mesg();
     57                 cout<<"Try again.
    ";
     58                 continue;   
     59             }
     60             catch(bad_gmean & hg)
     61             {
     62                 cout<<hg.mesg();
     63                 cout<<"Values used:"<<hg.v1<<" , "
     64                        <<hg.v2<<endl;
     65                 cout<<"Sorry,you don't get to play any more.
    ";
     66                 break;
     67             }
     68         }
     69         d1.show();
     70    }
     71    cout<<"Bye!
    ";
     72    cin.get();
     73    cin.get();
     74    return 0;
     75 }
     76 
     77 double hmean(double a, double b)
     78 {
     79     if(a == -b)
     80         throw bad_hmean(a,b);
     81     return 2.0*a*b/(a+b);
     82 }
     83 
     84 double gmean(double a, double b)
     85 {
     86     if(a<0||b<0)
     87         throw bad_gmean(a,b);
     88     return std::sqrt(a*b);
     89 }
     90 
     91 double means(double a, double b)
     92 {
     93     double am, hm, gm;
     94     demo d2("found in means()");
     95     am = (a+b)/2.0;
     96     try
     97     {
     98          hm = hmean(a,b);
     99          gm = gmean(a,b);
    100 
    101     }
    102     catch (bad_hmean & bg)
    103     {
    104         bg.mesg();
    105         std::cout<<"Caught in means()
    ";
    106         throw;   //重新抛出异常
    107     }
    108     d2.show();
    109     return (am+hm+gm)/3.0;
    110  
    111 }

    输出结果

    demo found in block in main() created

    Enter two numbers: 6 12

    demo found in means() created

    demo found in means() lives!

    demo found in means() destroyed

    The mean mean of 6 and 12 is 8.49509

    6 -6

    demo found in means() created

    hmean(6, -6):invalid arguments: a=-b

    Caught in means()

    demo found in means() destroyed             //d2被释放掉了,且来不及调用d2.show()

    hmean(6, -6):invalid arguments: a=-b       //异常重新抛出到main函数try块后面的catch

    Try again.                                                 //continue重新开始循环

    6 -8

    demo found in means() created              //d2被创建

    demo found in means() destroyed           //d2被释放,有异常产生,但是means函数中没有办法处理该异常gmean

    gmean() arguments should be >=0         //这个gmean异常被main函数的catch模块捕获并处理

    Values used: 6, -8

    Sorry, you don't get to play any more.      //直接break,结束

    demo found in block in main() lives!         //d1还在,程序运行到catch后面的语句

    demo found in block in main() destroyed   //离开了模块,d1被销毁

    Bye!

  • 相关阅读:
    冲刺第一天(补发)
    进度条05
    npm start问题
    Spring Boot 默认配置无法访问静态资源
    Spring Boot 返回Html界面
    阿里云配置tomcat后不能访问问题
    Spring Boot Web开发中Thymeleaf模板引擎的使用
    tomcat官网改版后下载方式
    Ubuntu16.04进入无限登录状态的解决办法
    Ubuntu16.04安装MySql5.7
  • 原文地址:https://www.cnblogs.com/grooovvve/p/10435112.html
Copyright © 2011-2022 走看看