C++中异常处理的基本思想及throw语句抛出异常的使用

异常处理基本思想
C++的异常处理的基本思想大致可以概括为传统错误处理机制、通过函数返回值来处理错误。

1)C++的异常处理机制使得异常的引发和异常的处理不必在同一个函数中,这样底层的函数可以着重解决具体问题,而不必过多的考虑异常的处理。上层调用者可以再适当的位置设计对不同类型异常的处理。
2)异常是专门针对抽象编程中的一系列错误处理的,C++中不能借助函数机制,因为栈结构的本质是先进后出,依次访问,无法进行跳跃,但错误处理的特征却是遇到错误信息就想要转到若干级之上进行重新尝试,如图

3)异常超脱于函数机制,决定了其对函数的跨越式回跳。
4)异常跨越函数

异常基本语法

1) 若有异常则通过throw操作创建一个异常对象并抛掷。
2) 将可能抛出异常的程序段嵌在try块之中。控制通过正常的顺序执行到达try语句,然后执行try块内的保护段。
3) 如果在保护段执行期间没有引起异常,那么跟在try块后的catch子句就不执行。程序从try块后跟随的最后一个catch子句后面的语句继续执行下去。
4) catch子句按其在try块后出现的顺序被检查。匹配的catch子句将捕获并处理异常(或继续抛掷异常)。
5) 如果匹配的处理器未找到,则运行函数terminate将被自动调用,其缺省功能是调用abort终止程序。
6)处理不了的异常,可以在catch的最后一个分支,使用throw语法,向上扔
7)异常机制与函数机制互不干涉,但捕捉的方式是基于类型匹配。捕捉相当于函数返回类型的匹配,而不是函数参数的匹配,所以捕捉不用考虑一个抛掷中的多种数据类型匹配问题。
catch代码块必须出现在try后,并且在try块后可以出现多个catch代码块,以捕捉各种不同类型的抛掷。
异常机制是基于这样的原理:程序运行实质上是数据实体在做一些操作,因此发生异常现象的地方,一定是某个实体出了差错,该实体所对应的数据类型便作为抛掷和捕捉的依据。
8)异常捕捉严格按照类型匹配
 异常捕捉的类型匹配之苛刻程度可以和模板的类型匹配媲美,它不允许相容类型的隐式转换,比如,抛掷char类型用int型就捕捉不到.例如下列代码不会输出“int exception.”,从而也不会输出“That's ok.” 因为出现异常后提示退出

int main(){
  try{
    throw ‘H';
  }
  catch (int){
    cout << "int exception.\n";
  }
  cout << "That's ok.\n"; 

  return 0;
}

栈解旋(unwinding)
异常被抛出后,从进入try块起,到异常被抛掷前,这期间在栈上的构造的所有对象,都会被自动析构。析构的顺序与构造的顺序相反。这一过程称为栈的解旋(unwinding)。

#include <iostream>
#include <cstdio>
using namespace std; 

class MyException {}; 

class Test
{
public:
  Test(int a = 0, int b = 0)
  {
    this->a = a;
    this->b = b;
    cout << "Test 构造函数执行" << "a:" << a << " b: " << b << endl;
  }
  void printT()
  {
    cout << "a:" << a << " b: " << b << endl;
  }
  ~Test()
  {
    cout << "Test 析构函数执行" << "a:" << a << " b: " << b << endl;
  }
private:
  int a;
  int b;
}; 

void myFunc() throw (MyException)
{
  Test t1;
  Test t2; 

  cout << "定义了两个栈变量,异常抛出后测试栈变量的如何被析构" << endl; 

  throw MyException();
} 

int main()
{
  //异常被抛出后,从进入try块起,到异常被抛掷前,这期间在栈上的构造的所有对象,
  //都会被自动析构。析构的顺序与构造的顺序相反。
  //这一过程称为栈的解旋(unwinding)
  try
  {
    myFunc();
  }
  //catch(MyException &e) //这里不能访问异常对象
  catch (MyException) //这里不能访问异常对象
  {
    cout << "接收到MyException类型异常" << endl;
  }
  catch (...)
  {
    cout << "未知类型异常" << endl;
  } 

  return 0;
}

异常接口声明
1)为了加强程序的可读性,可以在函数声明中列出可能抛出的所有异常类型,例如:
void func() throw (A, B, C , D); //这个函数func()能够且只能抛出类型A B C D及其子类型的异常。
2)如果在函数声明中没有包含异常接口声明,则次函数可以抛掷任何类型的异常,例如:
void func();
3)一个不抛掷任何类型异常的函数可以声明为:
void func() throw();
4) 如果一个函数抛出了它的异常接口声明所不允许抛出的异常,unexpected函数会被调用,该函数默认行为调用terminate函数中止程序。

传统处理错误

#include <iostream>
#include <cstdio>
using namespace std; 

// 传统的错误处理机制
int myStrcpy(char *to, char *from)
{
  if (from == NULL) {
    return 1;
  }
  if (to == NULL) {
    return 2;
  } 

  // copy时的场景检查
  if (*from == 'a') {
    return 3; // copy时错误
  }
  while (*from != '\0') {
    *to = *from;
    to++;
    from++;
  }
  *to = '\0'; 

  return 0;
} 

int main()
{
  int ret = 0;
  char buf1[] = "zbcdefg";
  char buf2[1024] = { 0 }; 

  ret = myStrcpy(buf2, buf1);
  if (ret != 0) {
    switch (ret) {
    case 1:
      cout << "源buf出错!\n";
      break;
    case 2:
      cout << "目的buf出错!\n";
      break;
    case 3:
      cout << "copy过程出错!\n";
      break;
    default:
      cout << "未知错误!\n";
      break;
    }
  }
  cout << "buf2:\n" << buf2;
  cout << endl; 

  return 0;
}

throw char*

#include <iostream>
#include <cstdio>
using namespace std; 

// throw char *
void myStrcpy(char *to, char *from)
{
  if (from == NULL) {
    throw "源buf出错";
  }
  if (to == NULL) {
    throw "目的buf出错";
  } 

  // copy时的场景检查
  if (*from == 'a') {
    throw "copy过程出错"; // copy时错误
  }
  while (*from != '\0') {
    *to = *from;
    to++;
    from++;
  }
  *to = '\0'; 

  return;
} 

int main()
{
  int ret = 0;
  char buf1[] = "abcdefg";
  char buf2[1024] = { 0 }; 

  try
  {
    myStrcpy(buf2, buf1);
  }
  catch (int e) // e可以写可以不写
  {
    cout << e << "int类型异常" << endl;
  }
  catch (char *e)
  {
    cout << "char* 类型异常" << endl;
  }
  catch (...)
  {
  };
  cout << endl; 

  return 0;
}

throw 类对象

#include <iostream>
#include <cstdio>
using namespace std; 

class BadSrcType {};
class BadDestType {};
class BadProcessType
{
public:
  BadProcessType()
  {
    cout << "BadProcessType构造函数do \n";
  } 

  BadProcessType(const BadProcessType &obj)
  {
    cout << "BadProcessType copy构造函数do \n";
  } 

  ~BadProcessType()
  {
    cout << "BadProcessType析构函数do \n";
  } 

};

throw 类对象、类型异常 

void my_strcpy3(char *to, char *from)
{
  if (from == NULL)
  {
    throw BadSrcType();
  }
  if (to == NULL)
  {
    throw BadDestType();
  } 

  //copy是的 场景检查
  if (*from == 'a')
  {
    printf("开始 BadProcessType类型异常 \n");
    throw BadProcessType(); //会不会产生一个匿名对象?
  } 

  if (*from == 'b')
  {
    throw &(BadProcessType()); //会不会产生一个匿名对象?
  } 

  if (*from == 'c')
  {
    throw new BadProcessType; //会不会产生一个匿名对象?
  }
  while (*from != '\0')
  {
    *to = *from;
    to++;
    from++;
  }
  *to = '\0';
} 

int main()
{
  int ret = 0;
  char buf1[] = "cbbcdefg";
  char buf2[1024] = { 0 }; 

  try
  {
    //my_strcpy1(buf2, buf1);
    //my_strcpy2(buf2, buf1);
    my_strcpy3(buf2, buf1);
  }
  catch (int e) //e可以写 也可以不写
  {
    cout << e << " int类型异常" << endl;
  }
  catch (char *e)
  {
    cout << e << " char* 类型异常" << endl;
  } 

  //---
  catch (BadSrcType e)
  {
    cout << " BadSrcType 类型异常" << endl;
  }
  catch (BadDestType e)
  {
    cout << " BadDestType 类型异常" << endl;
  }
  //结论1: 如果 接受异常的时候 使用一个异常变量,则copy构造异常变量.
  /*
  catch( BadProcessType e) //是把匿名对象copy给e 还是e还是那个匿名对象
  {
  cout << " BadProcessType 类型异常" << endl;
  }
  */
  /*结论2: 使用引用的话 会使用throw时候的那个对象
  catch( BadProcessType &e) //是把匿名对象copy给e 还是e还是那个匿名对象
  {
  cout << " BadProcessType 类型异常" << endl;
  }
  */ 

  //结论3: 指针可以和引用/元素写在一块 但是引用和元素不能写在一块
  catch (BadProcessType *e) //是把匿名对象copy给e 还是e还是那个匿名对象
  {
    cout << " BadProcessType 类型异常" << endl;
    delete e;
  } 

  //结论4: 类对象时, 使用引用比较合适  

  // --
  catch (...)
  {
    cout << "未知 类型异常" << endl;
  } 

  return 0;
}
(0)

相关推荐

  • 举例说明自定义C++异常处理的实例

    举例说明自定义C++异常处理的实例 例1:自定义一个继承自excepton的异常类myException C++标准中,定义在<stdexcept>中的任何异常类都派生自exception Class,本例也只是简单地由exception继承,在try段抛出一个异常并捕捉.代码如下: /*++ test.cpp version:1.0 decript:define a exception class named myException derived from base class excep

  • 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++异常的知识普及,有兴趣者也可以看看. 下面的代码直接贴到你的console工程中,可以运行调试看看效果,并分析c++的异常机制. 复制代码 代码如下: #include "stdafx.h" #include<stdlib.h> #include<crtdbg.h> #include <iostream> // 内存泄露检测机

  • C++之异常处理详解

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

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

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

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

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

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

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

  • C++中异常处理的基本思想及throw语句抛出异常的使用

    异常处理基本思想 C++的异常处理的基本思想大致可以概括为传统错误处理机制.通过函数返回值来处理错误. 1)C++的异常处理机制使得异常的引发和异常的处理不必在同一个函数中,这样底层的函数可以着重解决具体问题,而不必过多的考虑异常的处理.上层调用者可以再适当的位置设计对不同类型异常的处理. 2)异常是专门针对抽象编程中的一系列错误处理的,C++中不能借助函数机制,因为栈结构的本质是先进后出,依次访问,无法进行跳跃,但错误处理的特征却是遇到错误信息就想要转到若干级之上进行重新尝试,如图 3)异常超

  • php中异常处理方法小结

    本文实例总结了php中异常处理方法.分享给大家供大家参考.具体分析如下: 当异常被触发时,通常会发生:在PHP5中添加了类似于其它语言的错误异常处理模块.在 PHP代码中所产生的异常可被 throw语句抛出并被 catch 语句捕获.需要进行异常处理的代码都必须放入 try 代码块内,以便捕获可能存在的异常.每一个 try 至少要有一个与之对应的 catch. 使用多个 catch 可以捕获不同的类所产生的异常,当 try 代码块不再抛出异常或者找不到 catch 能匹配所抛出的异常时,PHP

  • 深入理解Java编程中异常处理的优劣

    Java编程中的异常处理是一个很常见的话题了,几乎任何一门介绍性的Java课程都会提到异常处理.不过,我认为很多人其实没有真正掌握正确处理异常情况的方法和策略,最多也就不过了解个大概,知道概念.我想对三种不同程度和质量的Java异常处理进行了讨论,所阐述的处理异常的方式按手法的高下分为:好,不好和恶劣三种.同时提供了一些解决这些问题的技巧.首先解释一些java异常处理中必须搞清楚的定义和机制.Java语言规范将自Error类或RuntimeException类衍生出来的任何违例都称作"不可检查&

  • C/C++中异常处理详解及其作用介绍

    目录 概述 异常处理 异常处理机制 函数声明指定异常 练习 案例一 案例二 概述 作为一名专业写 Bug, 编程一天改 bug 一周的程序媛. 学会异常处理是非常重要的. 我们不仅要考虑没有错误的理想情况, 更要考虑存在错误时的情况. Debug 可以帮助我们尽快发现错误, 消除错误. 错误类别: 语法错误 运行错误 逻辑错误 异常处理 设计程序时, 事先分析程序运行时可能出现的各种意外情况, 定制出相应的处理方法. 异常处理指对运行时出现的差错以及其他例外情况的处理. 没有异常处理程序时, 运

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

    目录 一.异常的引入 二.C++异常的关键字 三.异常的抛出与处理规则 四.异常缺陷的处理 五.自定义异常体系 六.异常规范 七.异常安全 八.异常的优缺点 1.优点 2.缺点 一.异常的引入 传统的C语言处理异常的方式有两种: 1.终止程序:使用assert断言语句,如果发生内存错误等,比如内存泄漏或者除0错误,都会直接终止程序. 2.返回错误码:通过错误码判断发生的异常的类型是什么,如系统的很多库的接口程序通过把错误码放到errno中,表示错误. 在实际中的C语言程序基本都是通过返回错误码的

  • javascript中异常处理案例(推荐)

    如下所示: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script type="text/javascript"> // cache 缓存 // try-catch-finall

  • Golang中异常处理机制详解

    前言 通常我们需要编写好的错误处理方式,在了避免某些程序员滥用异常,于是Go这里直接把异常这一块给砍掉了,最终还是通过返回值来判断程序的异常情况,毕竟Go可是支持多返回值的语言,比如atoi.itoa等函数,就不能忽略它的第二个返回值,因为第二个返回值代表了转换是否成功!不过Golang还是提供了一些错误处理机制的 Go的错误机制 1.没有异常机制 2.error类型实现了error接口 3.可以通过errors.New来快速创建错误实例 type error interface{ Error(

  • 关于Spring框架中异常处理情况浅析

    1.编写一个类,实现HandlerExceptionResolver接口 @Component public class ExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object

  • Python中异常处理用法

    目录 1.if进行处理,在错误发生之前进行预防 2.用try..except:在错误发生之后进行处理 为了保证程序的健壮性与容错性,即在遇到错误时候程序不会崩溃,我们需要对异常进行处理, 1.if进行处理,在错误发生之前进行预防 如果错误发生的条件是可预知的,我们需要用if进行处理,在错误发生之前进行预防 AGE=10 while True: age=input('>>: ').strip() if age.isdigit(): #只有在age为字符串形式的整数时,下列代码才不会出错,该条件是

  • SpringBoot中异常处理实战记录

    目录 一.背景 二.需求 三.编写一些异常基础代码 四.注意事项 五.总结 六.代码实现 七.参考文档 一.背景 在我们编写程序的过程中,程序中可能随时发生各种异常,那么我们如何优雅的处理各种异常呢? 二.需求 1.拦截系统中部分异常,返回自定义的响应. 比如: 系统发生HttpRequestMethodNotSupportedException异常,我们需要返回如下信息. http的状态码:返回 405 { code: 自定义异常码, message: 错误消息 } 2.实现自定义异常的拦截

随机推荐