C++Primer第五版 第十八章习题答案(1~10)
2017-03-20 09:26
567 查看
大规模应用程序的特殊要求
知识点1:异常处理:在独立开发的子系统之间协同处理错误的能力
知识点2:命名空间:使用各种库(可能包含独立开发的库)进行协同开发的能力
知识点3:多重继承:对比较复杂的应用概念建模的能力
1:知识点:C++通过抛出一个表达式来引发一个异常,throw之后的代码将不会被执行,程序控制权将从throw转移到与之匹配的catch模块(即捕获)(若try语句块还有嵌套,将继续在外层中寻找,称为栈展开),执行完这个catch语句之后,将转移到try块关联的最后一个catch子句之后的点,并从这里继续执行,若找不到与之匹配的catch语句,程序将调用标准库的terminate函数终止程序
答案:异常对象的类型皆是range_error
2:知识点1:栈展开的过程中对象会被自动销毁(所在块中创建的对象),若是类类型,该对象的析构函数将会自动执行
知识点2:析构函数总会执行,但是函数中负责释放资源的代码可能会被跳过(异常发生在负责释放资源的代码之前),但是类分配的对象无论函数正常结束还是遭遇异常,通过析构函数其资源都能够被正常释放(由于是自动执行的,所以析构函数中不应该抛出异常)
答案:发生异常,所在块之前的临时变量皆会被销毁,V会调用vector类的析构函数进行销毁,并释放相关内存,P指针会被销毁,但是P指针指向的内存由于是动态分配的,所以该内存不会被释放,造成内存泄漏。输入流对象会调用ifstream类的析构函数销毁,最后程序被终止
3:知识点1:throw抛出的表达式类型必须具有完全类型(如若是一个类,必须有完整的定义,不能仅仅只有声明)
知识点2:throw的抛出表达式若是一个指向局部对象的指针,那么肯定是错误的,因为其指向的内存会被释放,就类似于函数不能返回局部对象的指针一样(该块catch语句之前已经退出,对象已经被销毁)
知识点3:throw抛出的表达式是其静态编译的类型,也就是静态类型,所以不会发生动态绑定,若throw表达式解引用一个基类(基类的类型)指针,该指针指向的是派生类对象,则抛出的对象会被切除其派生类的部分
答案:只有指针P所分配的内存会出现错误,所以我们需要解决的问题是怎样在发生异常时,自动释放其指向的内存
1:使用智能指针,并传入删除的lambda表达式
2:使用类:创建一个包含一个int*的类,在析构函数进行delete文件指针
4:知识点1:catch子句中的异常声明看起来像是函数的形参列表,但是这个类型必须是完全类型,不能是右值引用。若其参数类型是非引用,则会传入一份异常对象的副本,若是引用,则是该对象的别名。
知识点2:若catch的参数是基类类型,我们可以使用派生类类型的异常声明对其进行初始化,如若不是引用方式,则会将派生类的部分切除。
知识点3:搜索匹配的catch语句过程中,找到的未必是最佳匹配,是第一个可以匹配的catch语句,所以越是专门、越是特例化的catch语句应该放在前面,因为catch语句是按照其出现顺序逐一匹配的
知识点4:catch语句参数类型允许的类型转换:非const到const、派生类到基类、数组元素到指针、函数名到指针这四种类型转换被允许
知识点5:若所个catch语句的类型之间存在这继承关系,应该将继承链的最低端的类放在前面
答案:由知识点3、5可知,应该将继承最低端的类放在最前面,顺序倒过来即可
5:复习一下P173相关知识,知识点:每个标准库异常类都包含了一个名为what的成员函数,这个函数没有参数,返回值是C风格的字符串(const char *),注意第四题知识点5
6:知识点1:捕获所有异常的处理代码:catch(...)可以与任何类型的异常匹配,左一该语句必须放在catch列表的最后位置
知识点2:catch语句通过重新抛出的操作将异常传递给另外一个catch,只需要在其体内加 throw;,通常情况下是因为catch语句需要改变其参数的内容,并想继续传播
(a):throw &exceptionType()
(b):任何异常皆可
(c):throw int()
7:知识点1:由于构造函数在其进入函数体之前进行初始化(执行初始化列表),所以此时的try语句块还未生效,所以构造函数体内的catch语句无法处理构造函数初始值列表抛出的异常,这是就需要构造函数try语句块的形式,即将初始值列表置于try语句块中(try语句块出现在:冒号之后以及函数体的花括号之前)
所有的构造函数都添加这个try语句块即可
8:知识点1:noexcep异常说明可以用来指定某个函数不会抛出异常(C++11新特性),声明和定义时皆需要出现在函数之后,但在final、override、=0之前
知识点2:noexcept用于两种情况:1:确认函数不会抛出异常 2:我们不知道如何处理异常
知识点3:异常说明还可以有实参,为bool类型,为true时,则函数不会抛出异常,为false时会抛出异常
知识点4:noexcept还可以作为运算符来使用,当其不跟在函数参数列表之后时,返回值是一个bool的常量表达式,为true时,表明传入参数会抛出异常
知识点5:函数指针和该指针所指的函数必须具有一致的异常说明
知识点6:如果一个虚函数承诺不抛出异常,则其派生类的相应虚函数需要作出同样的承诺
知识点7:若对所有成员和基类的操作都是noexcept的,则编译器合成版本的成员也是noexcept的
9:知识点1:exception表示的含义是某处出错,但错误细节未知,what是一个虚函数,所以引用捕获时会发生动态绑定
知识点2:自己定义的异常类型和标准库的异常类处理方式完全一样,一处抛出一处捕获
主要理解isbn_mismatch其实是一个继承的异常类
10:不捕获就发生异常,报错退出呗
知识点1:异常处理:在独立开发的子系统之间协同处理错误的能力
知识点2:命名空间:使用各种库(可能包含独立开发的库)进行协同开发的能力
知识点3:多重继承:对比较复杂的应用概念建模的能力
1:知识点:C++通过抛出一个表达式来引发一个异常,throw之后的代码将不会被执行,程序控制权将从throw转移到与之匹配的catch模块(即捕获)(若try语句块还有嵌套,将继续在外层中寻找,称为栈展开),执行完这个catch语句之后,将转移到try块关联的最后一个catch子句之后的点,并从这里继续执行,若找不到与之匹配的catch语句,程序将调用标准库的terminate函数终止程序
答案:异常对象的类型皆是range_error
2:知识点1:栈展开的过程中对象会被自动销毁(所在块中创建的对象),若是类类型,该对象的析构函数将会自动执行
知识点2:析构函数总会执行,但是函数中负责释放资源的代码可能会被跳过(异常发生在负责释放资源的代码之前),但是类分配的对象无论函数正常结束还是遭遇异常,通过析构函数其资源都能够被正常释放(由于是自动执行的,所以析构函数中不应该抛出异常)
答案:发生异常,所在块之前的临时变量皆会被销毁,V会调用vector类的析构函数进行销毁,并释放相关内存,P指针会被销毁,但是P指针指向的内存由于是动态分配的,所以该内存不会被释放,造成内存泄漏。输入流对象会调用ifstream类的析构函数销毁,最后程序被终止
3:知识点1:throw抛出的表达式类型必须具有完全类型(如若是一个类,必须有完整的定义,不能仅仅只有声明)
知识点2:throw的抛出表达式若是一个指向局部对象的指针,那么肯定是错误的,因为其指向的内存会被释放,就类似于函数不能返回局部对象的指针一样(该块catch语句之前已经退出,对象已经被销毁)
知识点3:throw抛出的表达式是其静态编译的类型,也就是静态类型,所以不会发生动态绑定,若throw表达式解引用一个基类(基类的类型)指针,该指针指向的是派生类对象,则抛出的对象会被切除其派生类的部分
答案:只有指针P所分配的内存会出现错误,所以我们需要解决的问题是怎样在发生异常时,自动释放其指向的内存
1:使用智能指针,并传入删除的lambda表达式
shared_ptr<int> p(new int[v.size()], [](int *p) { delete[] p; });//lambda表达式相当于一个删除器
2:使用类:创建一个包含一个int*的类,在析构函数进行delete文件指针
class intAr { int *p=nullptr; public: intAr(size_t n):p(new int ){} ~intAr() { delete[]p; } }
4:知识点1:catch子句中的异常声明看起来像是函数的形参列表,但是这个类型必须是完全类型,不能是右值引用。若其参数类型是非引用,则会传入一份异常对象的副本,若是引用,则是该对象的别名。
知识点2:若catch的参数是基类类型,我们可以使用派生类类型的异常声明对其进行初始化,如若不是引用方式,则会将派生类的部分切除。
知识点3:搜索匹配的catch语句过程中,找到的未必是最佳匹配,是第一个可以匹配的catch语句,所以越是专门、越是特例化的catch语句应该放在前面,因为catch语句是按照其出现顺序逐一匹配的
知识点4:catch语句参数类型允许的类型转换:非const到const、派生类到基类、数组元素到指针、函数名到指针这四种类型转换被允许
知识点5:若所个catch语句的类型之间存在这继承关系,应该将继承链的最低端的类放在前面
答案:由知识点3、5可知,应该将继承最低端的类放在最前面,顺序倒过来即可
5:复习一下P173相关知识,知识点:每个标准库异常类都包含了一个名为what的成员函数,这个函数没有参数,返回值是C风格的字符串(const char *),注意第四题知识点5
#include <iostream> #include <cstdlib> int main() { using namespace std; try { // } catch (overflow_error e) { cout << e.what(); abort(); } catch (underflow_error u) { cout << u.what(); abort(); } catch (range_error r) { cout << r.what(); abort(); } catch (domain_error d) { cout << d.what(); abort(); } catch (invalid_argument i) { cout << i.what(); abort(); } catch (out_of_range o) { cout << o.what(); abort(); } catch (length_error l) { cout << l.what(); abort(); } catch (runtime_error r) { cout << r.what(); abort(); } catch (logic_error l) { cout << l.what(); abort(); } catch (bad_alloc b) { cout << b.what(); abort(); } catch (bad_alloc b) { cout << b.what(); abort(); } catch (exception e) { cout << e.what(); abort(); } return 0; }
6:知识点1:捕获所有异常的处理代码:catch(...)可以与任何类型的异常匹配,左一该语句必须放在catch列表的最后位置
知识点2:catch语句通过重新抛出的操作将异常传递给另外一个catch,只需要在其体内加 throw;,通常情况下是因为catch语句需要改变其参数的内容,并想继续传播
(a):throw &exceptionType()
(b):任何异常皆可
(c):throw int()
7:知识点1:由于构造函数在其进入函数体之前进行初始化(执行初始化列表),所以此时的try语句块还未生效,所以构造函数体内的catch语句无法处理构造函数初始值列表抛出的异常,这是就需要构造函数try语句块的形式,即将初始值列表置于try语句块中(try语句块出现在:冒号之后以及函数体的花括号之前)
所有的构造函数都添加这个try语句块即可
template<typename T> Blob<T>::Blob() try:data(std::make_shared<std::vector<T>>()) { } catch (const std::bad_alloc &e) { std::cerr << e.what() << std::endl; }
8:知识点1:noexcep异常说明可以用来指定某个函数不会抛出异常(C++11新特性),声明和定义时皆需要出现在函数之后,但在final、override、=0之前
知识点2:noexcept用于两种情况:1:确认函数不会抛出异常 2:我们不知道如何处理异常
知识点3:异常说明还可以有实参,为bool类型,为true时,则函数不会抛出异常,为false时会抛出异常
知识点4:noexcept还可以作为运算符来使用,当其不跟在函数参数列表之后时,返回值是一个bool的常量表达式,为true时,表明传入参数会抛出异常
知识点5:函数指针和该指针所指的函数必须具有一致的异常说明
知识点6:如果一个虚函数承诺不抛出异常,则其派生类的相应虚函数需要作出同样的承诺
知识点7:若对所有成员和基类的操作都是noexcept的,则编译器合成版本的成员也是noexcept的
9:知识点1:exception表示的含义是某处出错,但错误细节未知,what是一个虚函数,所以引用捕获时会发生动态绑定
知识点2:自己定义的异常类型和标准库的异常类处理方式完全一样,一处抛出一处捕获
主要理解isbn_mismatch其实是一个继承的异常类
#include <iostream> #include <string> //18.9 struct out_of_stock :public std::runtime_error { explicit out_of_stock(const std::string &s) :std::runtime_error(s) {} }; struct isbn_mismatch :public std::logic_error { explicit isbn_mismatch(const std::string &s) :std::logic_error(s) {} isbn_mismatch(const std::string &s, const std::string &ls, const std::string &rs) :std::logic_error(s), left(ls), right(rs) {} std::string left; std::string right; };
10:不捕获就发生异常,报错退出呗
相关文章推荐
- C++Primer第五版 第八章习题答案(1~10)
- C++Primer第五版 第十三章习题答案(1~10)
- C++Primer第五版 第十章习题答案(1~10)
- C++Primer第五版 第十六章习题答案(1~10)
- C++Primer第五版 第九章习题答案(1~10)
- C++Primer第五版 第十八章习题答案(11~20)
- C++Primer第五版 第十八章习题答案(21~30)
- C++Primer第五版 第二章习题答案(1~10)
- C++Primer第五版 第四章习题答案(1~10)
- C++Primer第五版 第十九章习题答案(1~10)
- C++Primer第五版 第三章习题答案(1~10)
- C++Primer第五版 第七章习题答案(1~10)
- C++Primer第五版 第十一章习题答案(1~10)
- C++Primer第五版 第十二章习题答案(1~10)
- C++Primer第五版 第五章习题答案(1~10)
- C++Primer第五版 第十五章习题答案(1~10)
- C++Primer第五版 第九章习题答案(51~52)
- C++Primer第五版 第十五章习题答案(41~42)
- C++Primer 中文版 第五版 第二章课后习题答案
- C++Primer第五版——习题答案+详解(完整版)