C++ 异常的详细介绍

C++ 异常的详解

程序有时会遇到运行阶段错误,导致程序无法正常执行下去。c++异常为处理这种情况提供了一种功能强大的而灵活的工具。异常是相对比较新的C++功能,有些老编译器可能没有实现。另外,有些编译器默认关闭这种特性,我们可能需要使用编译器选项来启用它。

一、异常机制的使用

异常提供了将控制程序的一个部分传递到另一部分的途径。对异常的处理有3个组成部分:

引发异常
使用处理程序捕获异常
使用try块

示例代码:

#include "stdafx.h"
#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
    {
      z = hmean(x, y);
    }
    catch(const char *s ){
      std::cout << s << std::endl;
      std::cout << " Enter a new pair of numbers: ";
      continue;
    }
    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";
  system("pause");
  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);
}

Enter two numbers: 3 6
Harmonic mean of 3 and 6 is 4
Enter next set of numbers <q to quit>: 10 -10
bad hmean() arguments a= -b not allowed
 Enter a new pair of numbers: q
Bye!
请按任意键继续. . .

程序说明:

try块:

   try
    {
      z = hmean(x, y);
    }

引发异常的代码:

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

  }

执行throw语句类似于执行返回语句,因为他也将终止函数的执行;但throw不是讲控制权返回给调用程序,而是导致程序沿函数调用序列后退,知道找到包含try块的函数。

处理程序(或catch块):

catch(const char *s ){
      std::cout << s << std::endl;
      std::cout << " Enter a new pair of numbers: ";
      continue;
    }

二、将对象用作异常类型

通常,引发异常的函数将传递一个对象。这样做的重要优点之一是,可以使用不同的异常类型来区分不同的函数在不同情况下引发的异常。另外,对象可以携带信息,程序员可以根据这些信息来确定引发异常的原因。同时,catch块可以根据这些信息来决定采取什么样的措施。

示例:

exc_mean.h

#include "stdafx.h"
#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 argumnents: 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 shoud be >=0 \n";
}

测试代码:

#include "stdafx.h"
#include <iostream>
#include <cmath>
#include "exc_mean.h"

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;
  1 >> 2;
  cout << "Enter two numbers ";
  while (cin >> x >> y)
  {
    try
    {
      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 >:";
    }
    catch (bad_hmean & bg)
    {
      bg.mesg();
      cout << "Try again. \n";
      continue;
    }
    catch (bad_gmean & hg)
    {
      cout << hg.mesg();
      cout << "Value used: " << hg.v1 << " ," << hg.v2 << endl;
      cout << "Sorry, you don't get to play any more .\n ";
      break;
    }

  }
  cout << " Bye! \n";
  system("pause");
  return 0;
  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);
}

输出结果:
Enter two numbers 4 12
Harmonic mean of 4 and 12 is 6
 Geometric mean of 4 and 12 is 6.9282
 Enter next set of numbers <q to quit >:5 -5
hmean ( 5 ,-5) ;invalid argumnents: a =-b
Try again.
5 -2
Harmonic mean of 5 and -2 is -6.66667
gmean() arguments shoud be >=0
Value used: 5 ,-2
Sorry, you don't get to play any more .
 Bye!
请按任意键继续. . .

三、异常规范

异常规范是C++98的一项功能,但c++11将其摒弃了。这意味着c++11仍然处于标准之中,但以后可能会从标准中剔除,因此不建议使用它。

异常规范示例:

double harm(double a ) throw(bad_thing);//可能会抛出 bad_thing异常
double marm(double ) throw() ;//不抛出异常

异常规范的作用:

1、告诉用户可能需要使用try块,然而这项功能也可使用注释轻松完成。

2、让编译器添加执行运行阶段检查代码,检查是否违反了异常规范,然而这很难检查,例如marm可能不会引发异常,但它可能调用一个函数,而这个函数调用另一个函数引发了异常

总之最好不要使用这项功能,c++11也建议忽略异常规范

然而c++11确实支持一种特殊的异常规范,可使用关键字noexcept

例如

double marm() noexcept;

四、栈解退

假设函数由于异常(而不是由于返回)而终止,则程序也将释放栈中的内存,但不会师范栈的第一个返回地址后停止,而是继续释放栈,直到找到一个位于Try块的返回地址。随后,控制权将转到块尾的异常处理程序,而不是函数调用后面的第一条语句。这个过程叫做栈解退。

五、exception类

较新的C++编译器将异常合并到语言中,例如,为支持该语言,exception头文件(以前为exception.h 或except.h)定义了 exception类,c++可以把它用作其他异常类的基类。

头文件 exceptionhe 和 stdexcept 定义了一些常用的异常类

有:logic_error、runtime_error、domain_error 等

六、意外异常与未捕获异常处理

异常引发后,在两种情况下,会导致问题。首先,如果它是在带异常规范的函数中引发的,则必须与规范列表的某种异常匹配(在继承层次机构中,类类型与这个类与其派生的对象匹配),否则成为意外异常。在默认情况下,这将导致程序异常终止(虽然C++11摒弃了异常规范,但仍支持它,且有些现有代码使用了它)如果异常不是在函数中引发的(或者函数没有异常规范),则必须捕获它,如果没有捕获(在没有try块或没有匹配的catch块时,将出现这种情况),则异常被称未捕获异常。这将导致程序异常终止。然而可以修改程序对意外异常和为捕获异常的反应。

未捕获异常:

未捕获异常不会导致程序立即异常中终止,相反,程序将首先调用函数terminate()。在默认情况下terminate()调用abort()函数。可以指定terminate()应调用的函数(而不是abort())来修改terminate()的这种行为。为此,可调用set_terminate()函数。set_terminate()和terminate()都是在头文件exception中声明的:

typedef void (*terminate_handle)() ;
terminate_handle set_terminate(terminate_handle f) throw();//c++ 98
terminate_handle set_terinate(terminate_handle f) noexcept; //c++11
void teminate(); //c++98
void teminate() noexcept ; //c++11

示例:

void myQuit()
{
  std::cout << "Terminating due to uncaught exception \n";

  system("pause");
}

在程序开始时执行:
set_terminate(myQuit);

意外异常

如果发生意外异常,程序将调用unexcepted()函数,这个函数将调用teminate(),后者默认滴啊用abort()。和set_terminate()函数一样,也有一个可用于修改unexcepted()的行为的set_unexpeceted()函数。这些函数也是在头文件exception中声明的:

typedef void (* unexpected_handle)();
unexpected_handle set_unexpected(unexpected_handle f) throw();//c++98
unexpected_handle set_unexpected(unexpected_handle f) noexpect;//c++11
void unexpected(); c++ 98
void unexpected() noexcept ;//c+ 0x

使用如下:

void myUnexpected() {
  throw std::bad_exception(); // or just throw ;
}
在程序开始时:set_unexpected(myUnexpected);

我在vs 2015下测试,并未实现这种功能,必须显示调用terminate() 和 unexpected();

如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

(0)

相关推荐

  • 解析C++编程中异常相关的堆栈展开和throw()异常规范

    C++ 中的异常和堆栈展开 在 C++ 异常机制中,控制从 throw 语句移至可处理引发类型的第一个 catch 语句.在到达 catch 语句时,throw 语句和 catch 语句之间的范围内的所有自动变量将在名为"堆栈展开"的过程中被销毁.在堆栈展开中,执行将继续,如下所示: 控制通过正常顺序执行到达 try 语句.执行 try 块内的受保护部分. 如果执行受保护的部分的过程中未引发异常,将不会执行 try 块后面的 catch 子句.执行将在关联的 try 块后的最后一个 c

  • c++异常处理机制示例及详细讲解

    这两天我写了一个测试c++异常处理机制的例子,感觉有很好的示范作用,在此贴出来,给c++异常处理的初学者入门.本文后附有c++异常的知识普及,有兴趣者也可以看看. 下面的代码直接贴到你的console工程中,可以运行调试看看效果,并分析c++的异常机制. 复制代码 代码如下: #include "stdafx.h" #include<stdlib.h> #include<crtdbg.h> #include <iostream> // 内存泄露检测机

  • 解析C++编程中的bad_cast异常

    由于强制转换为引用类型失败,dynamic_cast 运算符引发 bad_cast 异常. 语法 catch (bad_cast) statement 备注 bad_cast 的接口为: class bad_cast : public exception { public: bad_cast(const char * _Message = "bad cast"); bad_cast(const bad_cast &); virtual ~bad_cast(); }; 以下代码包

  • C++的try块与异常处理及调试技术实例解析

    本文以示例形式简述了C++ try块的异常处理与调试技术,有助于读者复习并加深对try块的了解. 一.格式: 抛出异常throw 异常类型例如throw runtime_error("Data must refer to same ISBN"); try{ program-statements }catch(exception-specifier) { handler-statement; }catch(exception-specifier) { handler-statement;

  • C++中的异常处理机制详解

    异常处理 增强错误恢复能力是提高代码健壮性的最有力的途径之一,C语言中采用的错误处理方法被认为是紧耦合的,函数的使用者必须在非常靠近函数调用的地方编写错误处理代码,这样会使得其变得笨拙和难以使用.C++中引入了异常处理机制,这是C++的主要特征之一,是考虑问题和处理错误的一种更好的方式.使用错误处理可以带来一些优点,如下: 错误处理代码的编写不再冗长乏味,并且不再和正常的代码混合在一起,程序员只需要编写希望产生的代码,然后在后面某个单独的区段里编写处理错误的嗲吗.多次调用同一个函数,则只需要某个

  • C++运行时获取类型信息的type_info类与bad_typeid异常

    type_info 类 type_info 类描述编译器在程序中生成的类型信息.此类的对象可以有效存储指向类型的名称的指针. type_info 类还可存储适合比较两个类型是否相等或比较其排列顺序的编码值.类型的编码规则和排列顺序是未指定的,并且可能因程序而异. 必须包含 <typeinfo> 标头文件才能使用 type_info 类. type_info 类的接口是: class type_info { public: virtual ~type_info(); size_t hash_co

  • C++之异常处理详解

    程序中的错误分为编译时的错误和运行时的错误.编译时的错误主要是语法错误,比如:句尾没有加分号,括号不匹配,关键字错误等,这类错误比较容易修改,因为编译系统会指出错误在第几行,什么错误.而运行时的错误则不容易修改,因为其中的错误是不可预料的,或者可以预料但无法避免的,比如内存空间不够,或者在调用函数时,出现数组越界等错误.如果对于这些错误没有采取有效的防范措施,那么往往会得不到正确的运行结果,程序不正常终止或严重的会出现死机现象.我们把程序运行时的错误统称为异常,对异常处理称为异常处理.C++中所

  • C++ 异常处理 catch(...)介绍

    如果要想使一个catch block能抓获多种数据类型的异常对象的话,怎么办?C++标准中定义了一种特殊的catch用法,那就是" catch(-)". 感性认识 1.catch(-)到底是一个什么样的东东,先来个感性认识吧!看例子先: 复制代码 代码如下: int main() { try { cout << "在 try block 中, 准备抛出一个异常." << endl; //这里抛出一个异常(其中异常对象的数据类型是int,值为1

  • 了解C++编程中指定的异常和未经处理的异常

    noexcept C++11:指定函数是否可能会引发异常. 语法 ReturnType FunctionName(params) noexcept; ReturnType FunctionName(params) noexcept(noexcept(expression); 参数 表达式 计算结果是 True 或 False 的常量表达式.无条件版本相当于 noexcept(true). 备注 noexcept(及其同义词 noecept(true))指定函数绝不会引发异常,或允许从异常直接或间

  • C++编程异常处理中try和throw以及catch语句的用法

    若要在 C++ 中实现异常处理,你可以使用 try.throw 和 catch 表达式. 首先,使用 try 块将可能引发异常的一个或多个语句封闭起来. throw 表达式发出信号,异常条件(通常是错误)已在 try 块中发生.你可以使用任何类型的对象作为 throw 表达式的操作数.该对象一般用于传达有关错误的信息.大多数情况下,建议你使用 std::exception 类或标准库中定义的派生类之一.如果其中的类不合适,建议你从 std::exception 派生自己的异常类. 若要处理可能引

随机推荐