1.栈展开过程沿着嵌套函数的调用链不断查找,直到找到了与异常匹配的catch句子为止,或者也可能一直没找到匹配的catch,则程序将调用terminate,退出主函数后查找过程终止。假设找到了一个catch,则执行其中的代码,执行完之后,找到与try块关联的最后一个catch子句之后的点,并从这里继续执行。

2.如果在栈展开过程中推出了某个块,编译器将负责确保在这个块中创建的对象能被正确销毁,如果异常发生在构造函数中,即使某个对象只构造了一部分,我们也要确保已构造的成员能被正确地销毁。

3.在栈展开的过程中,运行类类型的局部对象的析构函数。因为这些析构函数是自动执行的,所以它们不应该抛出异常,如果要抛出异常,则应该在析构函数内部得到处理。一旦在栈展开的过程中析构函数抛出了异常,并且析构函数自身没能捕获到该异常,则程序将被终止。

4.异常对象是一种特殊对象,编译器使用异常抛出表达式来对异常对象进行拷贝初始化。因此throw语句中的表达式必须拥有完全类型。而且如果该表达式是类类型的话,则相应的类必须含有一个可访问的析构函数和一个可访问的拷贝或移动构造函数。如果是数组类型或函数类型,则表达式将被转换成与之对应的指针类型。

5.异常对象位于编译器管理的空间中,编译器确保无论最终调用的是哪个catch子句都能访问该空间。当异常处理完毕后,异常对象被销毁。

6.当我们抛出一条表达式时,该表达式的静态编译时类型决定了异常对象的类型。如果throw解引用一个指向派生类的基类指针,则抛出的对象将被切掉派生类的部分。

7.声明的类型决定了处理代码所能捕获的异常类型,这个类型必须是完全类型,它可以是左值引用,但不能是右值引用。

8.通常情况下,如果catch接受的异常与某个继承体系有关,则最好将该catch的参数定义成引用类型。

9.在搜寻catch语句的过程中,挑选出来的应该是第一个与异常匹配的catch语句,因此,越是专门的catch越应该置于整个catch列表前端。

10.异常声明中绝大多数类型转换都不被允许,除了以下几点情况:

  • 允许从非常量向常量的类型转换
  • 允许派生类向基类的类型转换
  • 数组或函数被转换成指针

11.有时候一个单独的catch语句不能完整地处理某个异常,可以通过重新抛出的操作将异常传递给另外一个catch语句,这里的重新抛出仍然是一条throw,只不过不包含任何表达式,空throw语句只能出现在catch语句或catch语句直接或间接调用的函数之内。如果在其他地方使用,编译器将调用terminate。很多时候,catch语句会改变其参数的内容,只有当异常声明是引用类型时,重新抛出的参数才会保留改变的内容继续传播。

struct test
{
int *id = nullptr;
int *count = nullptr;
}; struct testex : public test
{ }; testex t; void dotest()
{
try
{
if (!t.id)
throw t;  // 这里实际上对t做了拷贝
}
catch (testex &e)
{
e.id = new int();
if(!t.count)
throw;
}
} int main()
{
try
{
dotest();
}
catch (test e)
{
e.count = new int(); // 这里的e的id已经指向1
} // 注意,到这里我们的全局变量t没有任何变化,如果想要t被改变,我们应该throw t的指针,即throw &t;
return ;
}

12.为了一次性捕获所有的异常类型,我们使用省略号作为异常声明,如果catch(...)与其他几个catch语句一起出现,则catch(...)必须在最后的位置,出现在捕获所有异常语句后面的catch语句将永远不会被匹配。

13.构造函数体内的catch语句无法处理构造函数初始值列表抛出的异常。我们可以将构造函数写成函数try语句块的形式,这样既能处理构造函数体,也能处理构造函数的初始化过程。但是注意,在初始化构造函数的参数时也可能发生异常,这样的异常不属于函数try语句块的一部分,所以无法处理。

14.在C++11新标准中,我们可以通过提供noexcept说明指定某个函数不会抛出异常。紧跟在函数的参数列表后面,要跟在const及引用限定符之后,在final,override或虚函数的=0之前。

15.编译器并不会在编译时检查noexcept说明,如果一个函数在说明了noexcept的同时又含有throw语句或者调用了可能抛出异常的其他函数,编译器将顺利编译过。一旦一个noexcept函数抛出了异常,程序就会调用terminate以确保遵守不在运行时抛出异常的承诺,上述过程对是否执行栈展开未作约定,因此noexcept可以用在两种情况之下:

  • 我们确认函数不会抛出异常
  • 我们根本不知道该如何处理异常

16.noexcept说明符的实参常常与noexcept运算符混合使用,它是一个一元运算符,返回值是一个bool类型的右值常量表达式,用于表示给定的表达式是否会抛出异常。和sizeof类似,noexcept也不会求其运算对象的值。

void test() noexcept(true);    // 不会抛出异常

void test1()
{
test();
} void test2() noexcept(test1); // test1调用的所有函数都做了不抛出说明并且test1本身不含有throw语句时,表达式为true

17.如果我们为某个指针做了不抛出异常的声明,则该指针将只能指向不抛出异常的函数。如果一个虚函数承诺了它不会抛出异常,则后续派生出来的虚函数也必须做出同意的承诺。

void test() noexcept(true);    // 不会抛出异常
void test1() noexcept(false); // 可能会抛出异常 void(*pf)(void) noexcept = test; // 正确
void(*pf1)(void) noexcept = test1; // 错误 class base
{
public:
virtual void add(int) noexcept {};
}; class sub : public base
{
public:
void add(int) {} //错误
};

18.标准库异常类的继承体系如下,我们可以直接使用也可以继承它们定义自己的异常类型。

C++ Primer 笔记——异常处理的更多相关文章

  1. C++ Primer笔记

    C++ Primer笔记 ch2 变量和基本类型 声明 extern int i; extern int i = 3.14;//定义 左值引用(绑定零一变量初始值,别名) 不能定义引用的引用:引用必须 ...

  2. C++ Primer 笔记(1)基础中的战斗机 输入输出 对输入不定数据处理

    今天打算再重新好好的看一遍C++ Primer这本很经典的书籍,笔记开始: 1.每个C++程序都包含一个或者多个函数,其中必须有一个main,操作系统通过调用main入手运行程序: 2.函数包括:返回 ...

  3. C++ Primer 笔记 第一章

    C++ Primer 学习笔记 第一章 快速入门 1.1 main函数 系统通过调用main函数来执行程序,并通过main函数的返回值确定程序是否成功执行完毕.通常返回0值表明程序成功执行完毕: ma ...

  4. C++primer笔记之顺序容器

    最近又重新拾起C++primer,发现每一次看都会有不同的体验,但每一次看后因为不常用,忘记得很快,所以记笔记是很关键的一环,咋一看是浪费时间,实际上是节省了很多时间.下面就把这一节的内容做一个简单的 ...

  5. c++ primer 笔记 (一)

    昨天开始看的<C++ Primer>,确实不错.希望这周抓紧看完,每天做下笔记,以便以后复习. main函数返回一个值给操作系统   操作系统通过main函数返回的值来确定程序是否成功执行 ...

  6. C++ Primer笔记(1)——连续读取数据、类型对应的尺寸、类型转换、字符串分行写法

    这次要看看C++ Primer,这本基本上就是必读书籍了.下面的内容就是一些之前没有学过的知识的笔记. 读取数量不定的输入数据 虽然很简单,但是还是记一下: #include <iostream ...

  7. C++Primer笔记(3)

    标准库类型string表示可变长的字符序列,使用前先包含string头文件.(哈哈,终于可以逃脱C语言中的str函数系列了.)因为是标准库的一部分,所以string被定义在命名空间std中.所以你懂该 ...

  8. Python 2.7 学习笔记 异常处理

    如同别的开发语言,python也支持异常处理机制.本文介绍下它的基本语法. 一.异常的基本处理框架如下: try: 业务代码 except 异常类1: 异常处理代码 except 异常类2: 异常处理 ...

  9. C++ Primer 笔记 第三章

    C++ Primer 第三章 标准库类型 3.1using声明 例: using namespace atd; using std::cin; 3.2string类型 初始化方式 string s1 ...

随机推荐

  1. docker安装问题:E: Package 'docker-ce' has no installation candidate

    我的环境是在vm虚拟机中,Ubuntu17.04 前期安装步骤不过多介绍,下面这个博客就很好 ubuntu16.10安装docker17.03.0-ce并配置国内源和加速器 http://www.cn ...

  2. 多分类Logistics回归公式的梯度上升推导&极大似然证明sigmoid函数的由来

    https://blog.csdn.net/zhy8623080/article/details/73188671  也即softmax公式

  3. ajax传递数组,后台更新

    js: var rows = $("#stu_reg_table").datagrid("getSelections"); if(rows != "& ...

  4. exsi5.5以上版本支持虚拟机的二次虚拟化

    从存储里找到虚拟机的位置 下载并修改虚拟机的.vmx配置文件(记得做好备份) 打开<虚拟机名>.vmx文件,在末尾追加如下字段,保存退出. nce.enable = TRUE hyperv ...

  5. Python对HDFS的一些基础操作

    链接: http://www.cnblogs.com/shoufengwei/p/5949791.html

  6. npm & webpack

    npm 全称 node package manager,是 js 的包管理工具,开发人员可以把写好的框架.库发布到 npm 上,使用者在使用时候就可很方便地通过 npm 来下载,只要在 npm官网 有 ...

  7. 初次认识dedecms和帝国cms内容管理系统

    近乎完美的内容模块管理 强大的内容管理系统,细致入微 其原理都是 先建立一个 模板系统 然后动态生成静态页面 注意各个板块和栏目的设置  在迁移网站的时候 尤其需要注意的是 系统参数的 根目录 需要及 ...

  8. pl sql 中文乱码

    一:查看oracle数据库的字符集编码: select * fromnls_database_parameters where parameter in ('NLS_LANGUAGE', 'NLS_T ...

  9. VS2017编译LevelDB

    环境: 操作系统:Win7 x64 编译器:VS2017 需要Boost库支持,需要先将Boost库编译成为64位版本. 一.项目文件导入 1. 下载leveldb-windows,https://c ...

  10. mysql5.7 参数记录 (持续更新)

    sync_binlog 控制数据库的binlog刷到磁盘 默认sync_binlog=1,表示每次事务提交,MySQL都会把binlog刷下去,是最安全但是性能损耗最大的设置. sync_binlog ...