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 ...
随机推荐
- laravel 关闭 csrf 验证 TokenMismatchException
csrf验证失败 注释掉kernel.php 的 csrf 行代码
- P5270 无论怎样神树大人都会删库跑路
题目地址:P5270 无论怎样神树大人都会删库跑路 第一眼看上去是模拟,似乎是 \(O(n)\) 的 水题 信心满满的写完: #include <bits/stdc++.h> using ...
- Python-集合的常用操作
#!/usr/bin/env python # -*- coding:utf- -*- # Author:Irving list_1 = [,,,,,,,] list_1 = set(list_1) ...
- Python备份MySQL数据库【转】
#!/usr/bin/env python # coding: utf- import os import time ''' defined variable ''' databases=['hch' ...
- Android开发该学习哪些东西?
开篇: 本人也是众多Android开发道路上行走的一员,听了不少大神的知乎live,自己也看了不少书,也和不少前辈交流过,所以在这里分享一下Android开发应该学习的书籍以及知识,当然,也包括一些方 ...
- xargs命令的使用
xargs命令是给其他命令传递参数的一个过滤器,也是组合多个命令的一个工具. 它擅长将标准输入数据转换成命令行参数,xargs能够处理管道或者stdin并将其转换成特定命令的命令参数. xargs也可 ...
- Linux内核初探
内存管理之内存寻址 内存管理是迄今为止Unix内核中最复杂的活动 虚拟内存: 所有新近的Unix系统都提供一种有用的抽象, 叫作虚拟内存(virtual memory): 虚拟内存可以理解为一种逻辑层 ...
- 用Cordova打包Vue-vux项目
技术搭建:vue + vux 首先推荐阅读这篇文章,写的已经很详细了:https://www.jianshu.com/p/25d797b983cd 此处记录下我按照这篇文章打包的时候报的一些错误,方便 ...
- xl2tpd[26104]: Maximum retries exceeded for tunnel 33925. Closing
Sep 5 14:31:50 root charon: 13[ENC] generating QUICK_MODE request 3930082374 [ HASH ]Sep 5 14:31:5 ...
- IPNS节点ID
IPNS节点ID访问网站: 当我们修改网站内容重新添加到ipfs时,hash会发生变化,当我们网站更新时,我们可以将网站发布到IPNS,在IPNS中,允许我们节点的域名空间中引用一个IPFS ...