首页 > 编程语言 >c++ primer plus 第15章友,异常和其他:异常,15.3.3 异常机制

c++ primer plus 第15章友,异常和其他:异常,15.3.3 异常机制

时间:2024-07-08 20:59:03浏览次数:12  
标签:15.3 15 hmean double try bad catch 异常

#c++ primer plus 第15章友,异常和其他:异常,15.3.3 异常机制
异常,15.3.3 异常机制

文章目录


15.3.3 异常机制

15.3.3 异常机制

下面介绍如何使用异常机制来处理错误。C++异常是对程序运行过程中发生的异常情况(例如被0除)的一种响应。异常提供了将控制权从程序的一个部分传递到另一部分的途径。对异常的处理有3个组成部分:

  • 引发异常;
  • 使用处理程序捕获异常;
  • 使用 try 块。
  • 程序在出现问题时将引发异常。例如,可以修改程序清单15.7中的hmean(),使之引发异常,而不是调用 abort()函数。throw语句实际上是跳转,即命令程序跳到另一条语句。throw 关键字表示引发异常,紧随其后的值(例如字符串或对象)指出了异常的特征。

程序使用异常处理程序(exceptionhandler)来捕获异常,异常处理程序位于要处理问题的程序中。catch关键字表示捕获异常。处理程序以关键字catch开头,随后是位于括号中的类型声明,它指出了异常处理程序要响应的异常类型:然后是一个用花括号括起的代码块,指出要采取的措施。catch 关键字和异常类型用作标签,指出当异常被引发时,程序应跳到这个位置执行。异常处理程序也被称为 catch块。
try 块标识其中特定的异常可能被激活的代码块,它后面跟一个或多个 catch 块。try 块是由关键字 try指示的,关键字 try 的后面是一个由花括号括起的代码块,表明需要注意这些代码引发的异常。要了解这3个元素是如何协同工作的,最简单的方法是看一个简短的例子,如程序清单15.9所示。

程序清单 15.9error3.cpp

// error3.cpp -- using an exception
#include <iostream>
double hmean(double a, double b);

int main()
{
    double x, y, z;

    std::cout << "Enter two numbers: ";
    while (std::cin >> x >> y)
    {
        try {                   // start of try block
            z = hmean(x,y);
        }                       // end of try block
        catch (const char * s)  // start of exception handler
        {
            std::cout << s << std::endl;
            std::cout << "Enter a new pair of numbers: ";
            continue;
        }                       // end of handler
        std::cout << "Harmonic mean of " << x << " and " << y
            << " is " << z << std::endl;
        std::cout << "Enter next set of numbers <q to quit>: ";
    }
    std::cout << "Bye!\n";
    return 0;
}

double hmean(double a, double b)
{
    if (a == -b)
        throw "bad hmean() arguments: a = -b not allowed";
    return 2.0 * a * b / (a + b); 
}

程序说明
在程序清单 15.9中,try块与下面类似:

try {
z = hmean(x,y);
}
// start of try block
// end of try block

如果其中的某条语句导致异常被引发,则后面的 catch 块将对异常进行处理。如果程序在 try块的外面调用 hmean(),将无法处理异常。
引发异常的代码与下面类似:

if(a == -b)
throw "bad hmean()arguments:a=-b not allowed";

其中被引发的异常是字符串“bad hmean()arguments:a=-bnot allowed”。异常类型可以是字符串(就像这个例子中那样)或其他C++类型:通常为类类型,本章后面的示例将说明这一点。执行 throw 语句类似于执行返回语句,因为它也将终止函数的执行;但throw 不是将控制权返回给调用程序,而是导致程序沿函数调用序列后退,直到找到包含ty块的函数。在程序清单15.9中,该函数是调用函数。稍后将有一个沿函数调用序列后退多步的例子。另外,在这个例子中,throw 将程序控制权返回给 main()。程序将在 main()中寻找与引发的异常类型匹配的异常处理程序(位于try 块的后面)。处理程序(或catch块)与下面类似:

catch(char*s)//start of exception handler
std::cout <<s<<std::endl;
sdt::cout <<"Enter anew pair of numbers:";
continue;
//end of handler

catch 块点类似于函数定义,但并不是函数定义。关键字 catch 表明这是一个处理程序,而 chars则表明该处理程序与字符串异常匹配。s与函数参数定义极其类似,因为匹配的引发将被赋给s。另外,当异常与该处理程序匹配时,程序将执行括号中的代码。
执行完 try 块中的语句后,如果没有引发任何异常,则程序跳过tny块后面的 catch 块,直接执行处理程序后面的第一条语句。因此处理值3和6时,程序清单15.9中程序执行报告结果的输出语句。接下来看将 10和-10传递给 hmean()函数后发生的情况。If语句导致 hmean( )引发异常。这将终止
hmean()的执行。程序向后搜索时发现,hmean()函数是从 main()中的try块中调用的,因此程序查找与异常类型匹配的 catch 块。程序中唯一的一个 catch 块的参数为char
,因此它与引发异常匹配。程序将字符串“bad hmean( )arguments:a=-bnotallowed”赋给变量s,然后执行处理程序中的代码。处理程序首先打印 s–捕获的异常,然后打印要求用户输入新数据的指示,最后执行continue语句,命令程序跳过 while循环的剩余部分,跳到起始位置。continue使程序跳到循环的起始处,这表明处理程序语句是循环的一部分,而catch行是指引程序流程的标签(参见图15.2)。
在这里插入图片描述
您可能会问,如果函数引发了异常,而没有ty块或没有匹配的处理程序时,将会发生什么情况。在默认情况下下,程序最终将调用 abort()函数,但可以修改这种行为。稍后将讨论这个问题。
15.3.4 将对象用作异常类型
通常,引发异常的函数将传递一个对象。这样做的重要优点之一是,可以使用不同的异常类型来区分不同的函数在不同情况下引发的异常。另外,对象可以携带信息,程序员可以根据这些信息来确定引发异常的原因。同时,catch 块可以根据这些信息来决定采取什么样的措施。例如,下面是针对函数 hmean()引发的异常而提供的一种设计:

class bad_hmean
{
private :
double vl;
double v2;
public:

bad hmean(int a=0,intb=0):v1(a),v2(b){}
void mesg();
}
inline void bad hmean::mesg()
std::cout << "hmean(" << vl << "," << v2 <<"):
<< "invalid arguments:a=-bn";
}


可以将一个 bad hmean 对象初始化为传递给函数hmean()的值,而方法 mesg()可用于报告问题(包括传递给函数 hmena()的值)。函数hmean()可以使用下面这样的代码:

if(a == -b)
throw bad hmean(a,b);

上述代码调用构造函数bad hmean(),以初始化对象,使其存储参数值。程序清单 15.10和 15.11添加了另一个异常类 bad_gmean 以及另一个名为 gmean()的函数,该函数引发bad gmean 异常。函数 gmean()计算两个数的几何平均值,即乘积的平方根。这个函数要求两个参数都不为负,如果参数为负,它将引发异常。程序清单15.10是一个头文件,其中包含异常类的定义:而程序清单 15.11是一个示例程序,它使用了该头文件。注意,try块的后面跟着两个 catch 块:

try
{
// start of try block
...
}// end of try block
//start of catch blockcatch(bad hmean &bg)
catch(bad gmean &hg)
{
//end of catch block
}

如果函数 hmean()引发 bad_hmean 异常,第一个 catch块将捕获该异常;如果 gmean()引发bad_gmean异常,异常将逃过第一个catch块,被第二个catch 块捕获。

程序清单15.10exc mean.h

// exc_mean.h  -- exception classes for hmean(), gmean()
#include <iostream>

class bad_hmean
{
private:
    double v1;
    double v2;
public:
    bad_hmean(double a = 0, double b = 0) : v1(a), v2(b){}
    void mesg();
};

inline void bad_hmean::mesg()
{   
    std::cout << "hmean(" << v1 << ", " << v2 <<"): "
              << "invalid arguments: a = -b\n";
}

class bad_gmean
{
public:
    double v1;
    double v2;
    bad_gmean(double a = 0, double b = 0) : v1(a), v2(b){}
    const char * mesg();
};

inline const char * bad_gmean::mesg()
{  
    return "gmean() arguments should be >= 0\n";
}

程序清单 15.11error4.cpp

//error4.cpp ?using exception classes
#include <iostream>
#include <cmath> // or math.h, unix users may need -lm flag
#include "exc_mean.h"
// function prototypes
double hmean(double a, double b);
double gmean(double a, double b);
int main()
{
    using std::cout;
    using std::cin;
    using std::endl;
    
    double x, y, z;

    cout << "Enter two numbers: ";
    while (cin >> x >> y)
    {
        try {                  // start of try block
            z = hmean(x,y);
            cout << "Harmonic mean of " << x << " and " << y
                << " is " << z << endl;
            cout << "Geometric mean of " << x << " and " << y
                << " is " << gmean(x,y) << endl;
            cout << "Enter next set of numbers <q to quit>: ";
        }// end of try block
        catch (bad_hmean & bg)    // start of catch block
        {
            bg.mesg();
            cout << "Try again.\n";
            continue;
        }                  
        catch (bad_gmean & hg) 
        {
            cout << hg.mesg();
            cout << "Values used: " << hg.v1 << ", " 
                 << hg.v2 << endl;
            cout << "Sorry, you don't get to play any more.\n";
            break;
        } // end of catch block
    }
    cout << "Bye!\n";
    // cin.get();
    // cin.get();
    return 0;
}

double hmean(double a, double b)
{
    if (a == -b)
        throw bad_hmean(a,b);
    return 2.0 * a * b / (a + b);
}

double gmean(double a, double b)
{
    if (a < 0 || b < 0)
        throw bad_gmean(a,b);
    return std::sqrt(a * b); 
}

下面是程序清单15.10和15.11组成的程序的运行情况,错误的 gmean()函数输入导致程序终止:

首先,bad_hmean 异常处理程序使用了一条 continue语句,而bad_gmean 异常处理程序使用了一条 break语句。因此,如果用户给函数hmean()提供的参数不正确,将导致程序跳过循环中余下的代码,进入下一次循环;而用户给函数 gmean()提供的参数不正确时将结束循环。这演示了程序如何确定引发的异常(根据异常类型)并据此采取相应的措施。
其次,异常类 bad_gmean 和 bad hmean 使用的技术不同,具体地说,bad gmean 使用的是公有数据和一个公有方法,该方法返回一个C-风格字符串。

标签:15.3,15,hmean,double,try,bad,catch,异常
From: https://blog.csdn.net/zhyjhacker/article/details/140278639

相关文章

  • 题解:洛谷 P2678 [NOIP2015 提高组] 跳石头
    题解:洛谷P2678[NOIP2015提高组]跳石头标签:二分,贪心题意给定一个数列,\(a_0=0,a_{N+1}=L\),从其中删除不超过\(M\)个数,使得\(a_i-a_{i-1}\)的最小值最大。思路从最小值最大不难想到二分答案。统计\(a_i-a_j<mid\)的数量\(k\),如果不满足的话说明不删,\(j\getsi\)。......
  • Solution - Atcoder ARC150D Removing Gacha
    考虑到每次操作都比定会选上一个点,于是答案可以表示为每个点被选中的次数之和。即令\(c_i\)为\(i\)点被选中的次数,答案即为\(E(\sum\limits_{i=1}^nc_i)\)。根据期望的线性性,考虑把答案的\(E\)拆到每个\(c_i\)上,即变为\(\sum\limits_{i=1}^nE(c_i)\)的形式。......
  • C#中的异常捕获 try catch finally
    处理异常提供的四个关键字,try...catch...finally...throwfinally最后,不管异常是否被抛出都会执行,例如打开一个文件,不管是否出现异常都需要关闭,throw:当问题出现的时候程序可以抛出一个异常,使用throw关键字抛出异常,try{执行的代码}catch(ExceptionNamee1){处理异常t......
  • ROS2开发BUG记录:在将 use_sim_timer 置为 true 时,节点的 Timer_Callback 行为“异常”
    问题:在将use_sim_timer置为true时,节点Timer_Callback行为“异常”。在回调函数中,使用self.get_logger().info("xxxx")输出信息,希望通过查看Info中的时间戳(如下),测试Timer_Callback回调频率是否正常。发现该时间戳与预期回调频率不符。[target_server-7][INFO][17......
  • 深入理解Spring Boot中的异常处理机制
    深入理解SpringBoot中的异常处理机制大家好,我是微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!在任何应用程序开发中,异常处理都是至关重要的一部分。SpringBoot作为一个现代化的Java开发框架,提供了强大而灵活的异常处理机制,使开发者能够优雅地处理各种异常情况,保......
  • 塞尔达15座塔的在哪里在哪 塞尔达传说 荒野之息
    1.塞尔达阿卡莱之塔的位置如图所示,在阿卡莱地区2.塞尔达奥尔汀之塔的位置如图所示,在奥尔汀峡谷附近3.塞尔达初始之塔的位置如图所示4.塞尔达费罗尼之塔的位置如图所示,在花柔莉亚河附近5.塞尔达格鲁德之塔的位置如图所示6.塞尔达哈特诺之塔的位置如图所示,在哈特尔地区......
  • 应用程序无法正常启动(0xc0150002)的解决思路
    背景介绍一测试朋友,因为重装了操作系统,然后之前的工具突然无法使用了。现象现象1现象2解决现象1很显然,缺少运行库。你如果安装了visualstudio,那么其安装目录下xxx\MicrosoftVisualStudio\2019\Professional\VC\Redist\MSVC会存在需要的运行库或者是运行库安装......
  • Tool-Gitlab-重置数据库,修复server迁移token异常
    Tool-Gitlab-重置数据库,修复server迁移token异常迁移gitlab的server数据之后,导致token异常影响:修改工程配置信息,提交时页面报错502sudogitlab-railsdbconsole--databasemainDELETEFROMci_group_variables;DELETEFROMci_variables;UPDATEprojectsSETrunners_token......
  • 打卡信奥刷题(267)用Scratch图形化工具信奥P10415 [普及组][蓝桥杯 2023 国 A] 切割
    [蓝桥杯2023国A]切割题目描述给定一个W×HW\timesHW×H的长方形,两边长度均为整数。小蓝想把它切割为......
  • JAVA——异常
    异常Exception概念异常也就是非正常情况,比如使用空的引用、数组下标越界、内存溢出错误等,这些都是意外的情况,背离我们程序本身的意图。Java提供了异常对象描述这类异常情况。Java提供了异常机制来进行处理,通过异常机制来处理程序运行期间出现的错误。通过异常机制,可以更好......