C++ Primer 笔记——异常处理
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 笔记——异常处理的更多相关文章
- C++ Primer笔记
C++ Primer笔记 ch2 变量和基本类型 声明 extern int i; extern int i = 3.14;//定义 左值引用(绑定零一变量初始值,别名) 不能定义引用的引用:引用必须 ...
- C++ Primer 笔记(1)基础中的战斗机 输入输出 对输入不定数据处理
今天打算再重新好好的看一遍C++ Primer这本很经典的书籍,笔记开始: 1.每个C++程序都包含一个或者多个函数,其中必须有一个main,操作系统通过调用main入手运行程序: 2.函数包括:返回 ...
- C++ Primer 笔记 第一章
C++ Primer 学习笔记 第一章 快速入门 1.1 main函数 系统通过调用main函数来执行程序,并通过main函数的返回值确定程序是否成功执行完毕.通常返回0值表明程序成功执行完毕: ma ...
- C++primer笔记之顺序容器
最近又重新拾起C++primer,发现每一次看都会有不同的体验,但每一次看后因为不常用,忘记得很快,所以记笔记是很关键的一环,咋一看是浪费时间,实际上是节省了很多时间.下面就把这一节的内容做一个简单的 ...
- c++ primer 笔记 (一)
昨天开始看的<C++ Primer>,确实不错.希望这周抓紧看完,每天做下笔记,以便以后复习. main函数返回一个值给操作系统 操作系统通过main函数返回的值来确定程序是否成功执行 ...
- C++ Primer笔记(1)——连续读取数据、类型对应的尺寸、类型转换、字符串分行写法
这次要看看C++ Primer,这本基本上就是必读书籍了.下面的内容就是一些之前没有学过的知识的笔记. 读取数量不定的输入数据 虽然很简单,但是还是记一下: #include <iostream ...
- C++Primer笔记(3)
标准库类型string表示可变长的字符序列,使用前先包含string头文件.(哈哈,终于可以逃脱C语言中的str函数系列了.)因为是标准库的一部分,所以string被定义在命名空间std中.所以你懂该 ...
- Python 2.7 学习笔记 异常处理
如同别的开发语言,python也支持异常处理机制.本文介绍下它的基本语法. 一.异常的基本处理框架如下: try: 业务代码 except 异常类1: 异常处理代码 except 异常类2: 异常处理 ...
- C++ Primer 笔记 第三章
C++ Primer 第三章 标准库类型 3.1using声明 例: using namespace atd; using std::cin; 3.2string类型 初始化方式 string s1 ...
随机推荐
- ASP.NET MVC - 多国语言的简单实现
定义一个类 public class Book { public int ID { get; set; } public string Title { get; set; } ...
- 【转】python 面向对象(进阶篇)
[转]python 面向对象(进阶篇) 上一篇<Python 面向对象(初级篇)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 ...
- DevExpress VCL 的 cxDBTreeList 的使用方法
DevExpress VCL 的 cxDBTreeList 的使用方法:(假设控件名为: WBSTree) 1.控件WBSTree 通过绑定 DataSet 获取数据记录(Nodes),通过 Col ...
- MySQL查看表的索引【转】
查看表的索引: show index from table_name(表名) 结果列表中各字段的含义: · Non_unique 如果索引不能包括重复词,则为0.如果可以,则为1. · Key_nam ...
- expect学习笔记及实例详解
因为最近正在学习expect脚本,但是发现网上好多文章都是转载的,觉得这篇文章还不错,所以简单修改之后拿过来和大家分享一下~ 1. expect是基于tcl演变而来的,所以很多语法和tcl类似,基本的 ...
- html5 - Storage 本地存储
Storage的解释 http://www.w3school.com.cn/html5/html_5_webstorage.asp 简单的理解就是: Storage 有两种: 1.localStora ...
- 转-C语言中.h和.c文件解析
C语言中.h和.c文件解析(很精彩) 简单的说其实要理解C文件与头文件(即.h)有什么不同之处,首先需要弄明白编译器的工作过程,一般说来编译器会做以下几个过程: 1.预处理阶段 2.词 ...
- boost.Asio lib
Documentation for Boost.Asio http://www.boost.org/doc/libs/1_62_0/doc/html/boost_asio.html https://w ...
- Apache服务器和tomcat服务器有什么区别(转)
Apache与Tomcat都是Apache开源组织开发的用于处理HTTP服务的项目,两者都是免费的,都可以做为独立的Web服务器运行.Apache是Web服务器而Tomcat是Java应用服务器. A ...
- 基于MVC 的Quartz.Net组件实现的定时执行任务调度
新建mvc项目之后,首先引用Quartz组件.工具-->NuGet包管理器-->管理解决方案的 NuGet包管理器 组件安装完成. Quartz.Net一个最简单任务至少包括三部分实现:j ...