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. python - 字符编码/格式化/替换符

  2. MySql 在cmd下的学习笔记 —— 有关用户权限的操作(grant)

    用户连接到MySQL时: [用户]   <---->   [服务器] 分为2个阶段: 1:有没有权限连接: 2:有没有执行此操作的权利.(如select, update……) 判断依据:( ...

  3. android动态设置组件LayoutParams

    开发中经常用到动态设置组件的LayoutParams,之前开发遇到的问题如下: LinearLayout.LayoutParams params = new LinearLayout.LayoutPa ...

  4. Tensorflow的Queue读取数据机制

    参考链接:http://www.sohu.com/a/148245200_115128

  5. python3+requests库框架设计08-发送邮件

    使用python3的email模块和smtplib模块可以实现发送邮件的动能.email模块用来生成email,smtplib模块用来发送邮件,接下来看如何在生成测试报告之后,并将报告放在邮件附件中并 ...

  6. 常用的16个c/c++面试题

    1. C中static有什么作用 (1)隐藏. 当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性,故使用static在不同的文件中定义同名函数和同名变量,而不必担心命 ...

  7. hibernate框架学习之对象状态

    lHibernate对象共有三种状态 •瞬时状态:瞬时对象 •持久化状态:持久化对象 •托管状态:托管对象 l瞬时对象(Transient Object),简称TO l瞬时对象指的是应用程序创建出来的 ...

  8. windows下java环境变量的配置 javac不是内部或外部命令的问题

    安装配置JAVA JDK 下载地址:http://www.oracle.com/technetwork/java/javase/downloads/index.html . 下载你电脑对应的JDK,下 ...

  9. 在tomcat中添加虚拟主机,myeclipse中整合jdk和tomcat

    * 虚拟主机技术  ---- 在tomcat中配置 <Host> 元素  1.下载搭建tomcat中网站 --- baidu 2.在c盘 新建虚拟主机目录 baidu , 在虚拟主机目录中 ...

  10. struct/class等内存字节对齐问题详解

    问题引入 定义一个结构体的一般形式为: struct 结构体名 { //类型说明符 成员名; }; 例如有如下结构体: struct Stu { int id; char sex; float hig ...