一、程序错误

编译错误,即语法错误。程序就无法被生成运行代码。
运行时错误

不可预料的逻辑错误

可以预料的运行异常

例如:

动态分配空间时可能不会成功

打开文件可能会失败

除法运算时分母可能为0

整数相乘可能溢出

数组越界……

二、异常

(一)、异常语法

throw  表达式;

try
{
   //try语句块
}
catch(类型1  参数1)
{
   //针对类型1的异常处理
}
catch (类型2  参数2)
{
   //针对类型2的异常处理
}

catch (类型n  参数n)
{
   //针对类型n的异常处理
}

(二)、异常抛出

可以抛出内置类型异常也可以抛出自定义类型异常
throw抛出一个类对象会调用拷贝构造函数
异常发生之前创建的局部对象被销毁,这一过程称为栈展开

(三)、异常捕获

一个异常处理器一般只捕捉一种类型的异常
异常处理器的参数类型和抛出异常的类型相同
…表示可以捕获任何异常

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
 
#include <iostream>
#include <string>
using namespace std;

class MyException
{
public:
    MyException(const char *message)
        : message_(message)
    {
        cout << "MyException ..." << endl;
    }
    MyException(const MyException &other) : message_(other.message_)
    {
        cout << "Copy MyException ..." << endl;
    }
    ~MyException()
    {
        cout << "~MyException" << endl;
    }

const char *what() const
    {
        return message_.c_str();
    }
private:
    string message_;
};
double Divide(double a, double b)
{
    .)
    {
        MyException e("division by zero");
        throw e;
        /*throw MyException("division by zero");*/
        //throw 1;
    }
    else
        return a / b;
}
int main(void)
{
    try
    {
        cout << Divide(., .) << endl;
    }
    catch (MyException &e)
    {
        cout << e.what() << endl;
    }
    //catch (int)
    //{
    //  cout<<"int exception ..."<<endl;
    //}
    catch (double)
    {
        cout << "double exception ..." << endl;
    }
    catch (...)
    {
        cout << "catch a exception ..." << endl;
    }
}

程序自定义一个异常类型MyException,从输出可以看出,Divide函数内先构造一个MyException对象e,调用构造函数,因为e是局部对象需要被析构,在析构前先调用拷贝构造函数构造另一个对象,这个对象将被catch 引用,最后这个对象在catch末尾也将被析构。

假设没有构造局部对象,直接throw , 如 throw MyException("division by zero"); 那么将不会调用拷贝构造函数,只存在一个对象,在catch的末尾被析构。

假设throw 1; 而没有对应的catch (int) ,即使存在catch (double) 也捕获不到,不会做类型转换,此时会由catch (...) 捕获到,...表示可以捕获任何异常。

(四)、异常传播

1、try块可以嵌套
2、程序按顺序寻找匹配的异常处理器,抛出的异常将被第一个类型符合的异常处理器捕获
如果内层try块后面没有找到合适的异常处理器,该异常向外传播,到外层try块后面的catch块中寻找
3、没有被捕获的异常将调用terminate函数,terminate函数默认调用abort终止程序的执行
可以使用set_terminate函数指定terminate函数在调用abort之前将调用的函数

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 
void MyTerminate()
{
    cout << "MyTerminate ..." << endl;
}

int main(void)
{
    set_terminate(MyTerminate);
    try
    {
        try
        {
            throw MyException("test exception");
        }
        catch (int)
        {
            cout << "Inner ..." << endl;
            cout << "catch a int exception" << endl;
        }
        //catch (MyException& e)
        //{
        //  cout<<"Inner ..."<<endl;
        //  cout<<e.what()<<endl;
        //  throw e;
        //}
    }
    catch (int)
    {
        cout << "Outer ..." << endl;
        cout << "catch a int exception" << endl;
    }
    catch (MyException &e)
    {
        cout << "Outer ..." << endl;
        cout << e.what() << endl;
    }
}

其中MyException类如上,程序中将内层的catch (MyException& e) 屏蔽了,所以由外层的catch (MyException& e) 捕获,假设将两个都注释掉的话,因为没有找到合适的catch, 那么terminate 函数会被调用,并且由于事先set_terminate
函数设定了abort调用之前被调用的函数MyTerminate,故先输出MyTerminate ...然后程序被终止。

三、栈展开

沿着嵌套调用链接向上查找,直至为异常找到一个catch子句。这个过程称之为栈展开。

为局部对象调用析构函数

析构函数应该从不抛出异常

栈展开期间会执行析构函数,在执行析构函数的时候,已经引发的异常但还没处理,如果这个过程中析构函数又抛出新的异常,将会调用标准库的terminate函数。

异常与构造函数

构造函数中可以抛出异常。如果在构造函数函数中抛出异常,则可能该对象只是部分被构造。即使对象只是被部分构造,也要保证销毁已构造的成员。(如果成员是指针p,因为析构函数不会被调用,故不会执行一般的delete p; 很可能造成内存泄漏)

[转贴] 从零开始学C++之异常(二):程序错误、异常(语法、抛出、捕获、传播)、栈展开的更多相关文章

  1. Spring事务异常回滚,捕获异常不抛出就不会回滚(转载) 解决了我一年前的问题

    最近遇到了事务不回滚的情况,我还考虑说JPA的事务有bug? 我想多了.......    为了打印清楚日志,很多方法我都加tyr catch,在catch中打印日志.但是这边情况来了,当这个方法异常 ...

  2. cocos2d-x 错误异常抛出捕获和崩溃拦截

    Error对象 一旦代码解析或运行时发生错误,JavaScript引擎就会自动产生并抛出一个Error对象的实例,然后整个程序就中断在发生错误的地方. Error对象的实例有三个最基本的属性: nam ...

  3. C# 中异常抛出捕获机制--throw / try,catch,finally

    try { messagebox.show("true"); } catch { messagebox.show("false"); } finally { m ...

  4. 从零开始学Electron笔记(二)

    在之前的文章我们简单介绍了一下Electron可以用WEB语言开发桌面级应用,接下来我们继续说一下Electron的菜单创建和事件绑定. 我们接上一章的代码继续编写,上一章代码 https://www ...

  5. 从零开始学ios开发(二):Hello World!来啦!

    今天看了书的第二章,主要介绍了一下Xcode的使用方法和一些必要的说明,最后做了一个“Hello World!”的小程序,其实就是在屏幕上用一个Label显示“Hello World!”,一行代码都没 ...

  6. 从零开始学ios开发(二十):Application Settings and User Defaults(下)

    在上一篇的学习中,我们知道了如何为一个App添加它的Settings设置项,在Settings设置项中我们可以添加哪些类型的控件,这些控件都是通过一个plist来进行管理的,我们只需对plist进行修 ...

  7. 从零开始学安全(四十二)●利用Wireshark分析ARP协议数据包

    wireshark:是一个网络封包分析软件.网络封包分析软件的功能是撷取网络封包,并尽可能显示出最为详细的网络封包资料.Wireshark使用WinPCAP作为接口,直接与网卡进行数据报文交换,是目前 ...

  8. 从零开始学Linux系统(二)之基本操作指令

    ifconfigping ip地址帮助:ping -t ip地址ping -c 次数 ip地址ping -s 包的大小关机重启:shutdown -h now reboot清屏:clear  == C ...

  9. 从零开始学ios开发(二):Hello World!

    今天看了书的第二章,主要介绍了一下Xcode的使用方法和一些必要的说明,最后做了一个“Hello World!”的小程序,其实就是在屏幕上用一个Label显示“Hello World!”,一行代码都没 ...

  10. Spring事务异常回滚,捕获异常不抛出就不会回滚

    最近遇到了事务不回滚的情况,我还考虑说JPA的事务有bug? 我想多了.......    为了打印清楚日志,很多方法我都加tyr catch,在catch中打印日志.但是这边情况来了,当这个方法异常 ...

随机推荐

  1. JS 时间与时间戳的相互转换

    <script type="text/javascript"> var time = "2015-04-22 21:41:43";//2015-4- ...

  2. Java 链式编程

    这里来做一个Java 链式编程的例子,基本就是每次返回一个对象本身,这样就能够去调用对象的方法和属性. package com.sun; public class Demo05 { /** * @pa ...

  3. Retrofit研究1

    以下为来自Github的retrofit的介绍.话说,翻译还真蛋疼,就这个花了快3个小时. Retrofit 一个在Android和Java上类型安全的HTTP客户端 介绍 Retrofit可以把你的 ...

  4. 学习笔记_Filter小结(过滤器JavaWeb三大组件之一)

    Filter小结 Filter的三个方法: l  void init(FilterConfig):在Tomcat启动时被调用: l  void destroy():在Tomcat关闭时被调用: l  ...

  5. 获取API返回值

    //$return=getApiResult($url); // if ($return==200){ // //..... // } function getApiResult($url){ if( ...

  6. Oracle start with.connect by prior子句实现递归查询

    Oracle中的select语句可以用start with...connect by prior子句实现递归查询,connect by 是结构化查询中用到的,其基本语法是: select ... fr ...

  7. 05_Excel操作_01_简单导入导出

    [Excel组成] 主要由四部分组成: 1.工作簿 每一个Excel文件都可以看成是一个工作簿,当打开一个Excel文件时,相当于打开了一个Excel工作簿. 2.工作表 当打开了Excel工作簿后, ...

  8. 初学c++

    今天在计蒜客中学习了c++的语句编写方法.因为之前编程时候用的都是c,所以第一次看到c++的部分代码还是有点迷茫忙的. 初次接触c++,我学习到了c++中变量的定义以及输入输出. 代码如下: #inc ...

  9. Html代码Font-Size中px与pt的区别

    一个是设备坐标,一个是逻辑坐标,两者是不同的. px是个相对单位,一般像素的参考值为:在一个像素密度是90 pdi的显示器上,正常人从距离显示器28英寸处看一个像素的视角应该不小于0.0227度. 1 ...

  10. wcf通道Channel

    正文 客户端与服务进行交互的过程是通过通道进行交互的.客户端通过调用代理类执行相应的方法,通过通道编码,调用上下文,传输客户端的事务,管理可靠会话,对消息正文的加密,最后要执行的通道是传输通道就像我们 ...