C++ Primer第5版 第十八章课后练习答案
合集《C++ Primer第5版》 课后练习答案 - 丸子球球 - 博客园 (cnblogs.com)
练习18.1
(a)range_error;
(b)exception。
throw p,此时抛出的为指向局部对象的指针
练习18.2
p的内存没有释放,导致内存泄露
练习18.3
使用类对象
class vec_size
{
public:
vec_size():p(nullptr){}
vec_size(size_t size):p(new int[size]){}
~vec_size()
{
delete p;
}
private:
int* p;
};
使用智能指针
std::shared_ptr<int> p(new int[v.size()], [](int* p) { delete[] p; });
练习18.4
应该把异常类继承链层次最底端的类放在前面,而将继承链层次最顶端的类放在后面。
练习18.5
int main(int argc, char* argv[])
{
try{}
catch (const std::bad_cast& bc) {
cout << bc.what();
abort();
}
catch (const std::bad_alloc& ba) {
cout << ba.what();
abort();
}
catch (const std::overflow_error& oe) {
cout << oe.what();
abort();
}
catch (const std::underflow_error& ue) {
cout << ue.what();
abort();
}
catch (const std::range_error& re) {
cout << re.what();
abort();
}
catch (const std::runtime_error&re) {
cout << re.what();
abort();
}
catch (const std::domain_error&de) {
cout << de.what();
abort();
}
catch (const std::invalid_argument&ia) {
cout << ia.what();
abort();
}
catch (const std::out_of_range&oor) {
cout << oor.what();
abort();
}
catch (const std::length_error&le) {
cout << le.what();
abort();
}
catch (const std::logic_error&le) {
cout << le.what();
abort();
}
catch (const std::exception&e) {
cout << e.what();
abort();
}
}
练习18.6
(a)throw exceptionType *pet;
(b)throw exception();//可以捕获所有异常
(c)int a=1;throw a;
练习18.7
template <typename T>
Blob<T>::Blob()try :data(std::make_shared<vector<T>()>) {}
catch(const std::bad_alloc &e){
handle_out_of_memory(e);
}
template<typename T>
Blob<T>::Blob(std::initializer_list<T> il) try :data(make_shared<vector<T>>(il)) {}
catch(const std::bad_alloc &e){
handle_out_of_memory(e);
}
template <typename T>
BlobPtr<T>::BlobPtr()try:curr(0){}
catch (const std::bad_alloc& e) {
handle_out_of_memory(e);
}
template <typename T>
BlobPtr<T>::BlobPtr(Blob<T> &a, size_t sz = 0)try : wptr(a.data), curr(sz) {}
catch (const std::bad_alloc& e) {
handle_out_of_momory(e);
}
练习18.8
练习18.9
#ifndef SALES_DATA_H
#define SALES_DATA_H
#include <string>
#include <ostream>
template<class T>struct std::hash;
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;
};
class Sales_data {
friend struct std::hash<Sales_data>;
friend Sales_data operator+(Sales_data& lhs, Sales_data& rhs);
friend Sales_data operator-(Sales_data& lhs, Sales_data& rhs);
friend std::istream& operator>>(std::istream& is, Sales_data& it);
friend std::ostream& operator<<(std::ostream& os, const Sales_data& it);
friend bool operator==(const Sales_data& lhs, const Sales_data& rhs);
private:
string bookNo;
unsigned units_sold = { 0 };
double revenue = { 0.0 };
public:
const string& isbn() const { return bookNo; }
Sales_data& operator+=(const Sales_data& rhs) {
if (isbn() != rhs.isbn())
throw isbn_mismatch("wrong isbns", isbn(), rhs.isbn());
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
Sales_data& operator-=(const Sales_data& rhs) {
if (isbn() != rhs.isbn())
throw isbn_mismatch("wrong isbns", isbn(), rhs.isbn());
units_sold -= rhs.units_sold;
revenue -= rhs.revenue;
return *this;
}
Sales_data(string bn, unsigned us = 0, double re = 0.0) :bookNo(bn), units_sold(us), revenue(re) { std::cout << "Sales_data(string bn, unsigned us = 0, double re = 0.0)" << std::endl;}
Sales_data() :Sales_data("") { std::cout << "Sales_data()" << std::endl; }
Sales_data(std::istream& is) :Sales_data() { is>> *this; std::cout << "Sales_data(istream& is)" << std::endl; }
Sales_data& operator=(string&)noexcept;
explicit operator string() const { return bookNo; }
explicit operator double() const { return revenue; }
};
Sales_data operator+(const Sales_data& lhs,const Sales_data& rhs) {
if (lhs.isbn() != rhs.isbn())
throw isbn_mismatch("wrong isbns", lhs.isbn(), rhs.isbn());
Sales_data sum = lhs;
sum += rhs;
return sum;
}
Sales_data operator-(Sales_data& lhs, Sales_data& rhs) {
if (lhs.isbn() != rhs.isbn())
throw isbn_mismatch("wrong isbns", lhs.isbn(), rhs.isbn());
Sales_data sum = lhs;
sum -= rhs;
return sum;
}
std::istream & operator>>(std::istream& is, Sales_data& it) {
is >> it.bookNo >> it.units_sold >> it.revenue;
if (!is)
it = Sales_data();
return is;
}
std::ostream& operator<<(std::ostream& os, const Sales_data& it) {
os << it.isbn() << " " << it.units_sold << " " << it.revenue;
return os;
}
inline bool operator==(const Sales_data& lhs, const Sales_data& rhs)
{
return lhs.units_sold == rhs.units_sold &&
lhs.revenue == rhs.revenue &&
lhs.isbn() == rhs.isbn();
}
Sales_data& Sales_data::operator=(string& s)noexcept
{
bookNo = s;
units_sold = 0;
revenue = 0;
return *this;
}
namespace std {
template<>
struct hash<Sales_data>
{
typedef size_t result_type;
typedef Sales_data argument_type;
size_t operator()(const Sales_data& s)const;
};
size_t hash<Sales_data>::operator()(const Sales_data& s) const
{
return hash<string>()(s.bookNo)^ hash<unsigned>()(s.units_sold)^ hash<double>()(s.revenue);
}
}
#endif // !SALES_DATA_H
练习18.10
Sales_data operator+(const Sales_data& lhs,const Sales_data& rhs) {
if (lhs.isbn() != rhs.isbn())
throw isbn_mismatch("wrong isbns", lhs.isbn(), rhs.isbn());
Sales_data sum = lhs;
sum += rhs;
return sum;
}
Sales_data operator+(const Sales_data& lhs,const Sales_data& rhs) {
Sales_data sum = lhs;
sum += rhs;
return sum;
}
出现一个未被捕获的异常时,程序将会执行terminate。
练习18.11
what中如果抛出异常,需要try catch捕获,再调用what,一直循环,直达内存耗尽。
练习18.12
#include <fstream>
using std::ifstream;
using std::ofstream;
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
#include <map>
using std::map;
using std::multimap;
#include <set>
using std::multiset;
using std::set;
#include <sstream>
using std::istringstream;
#include <string>
using std::string;
#include <unordered_map>
using std::unordered_map;
#include <vector>
#include "StrVec.h"
#include <algorithm>
using std::vector;
#ifndef TEXTQUERT_H_
#define TEXTQUERT_H_
#include "DebugDelete.h"
namespace chapter10 {
class QueryResult;
class TextQuery
{
friend class QueryResult;
public:
TextQuery() :text(new StrVec, DebugDelete("TextQuery::StrVec")), query_words(new map<string, std::shared_ptr<set<size_t>>>, DebugDelete("TextQuery::map<string, std::shared_ptr<set<size_t>>>")) {}
TextQuery(ifstream& ifs);
QueryResult query(string s) const;
~TextQuery();
private:
std::shared_ptr <StrVec> text;
std::shared_ptr<map<string, std::shared_ptr<set<size_t>>>> query_words;
};
class QueryResult
{
public:
friend std::ostream& print(std::ostream& os, const QueryResult qr);
using QueryIterator = set<size_t>::iterator;
public:
QueryResult(string& w, std::shared_ptr<set<size_t>> n, std::shared_ptr<StrVec> i) :word(w), nos(new set<size_t>, DebugDelete("QueryResult::set<size_t>")), inputs(new StrVec, DebugDelete("QueryResult::StrVec")) {
nos = n;
inputs = i;
}
~QueryResult();
QueryIterator begin() { return nos->begin(); }
QueryIterator end() { return nos->end(); }
std::shared_ptr <StrVec> get_file() { return inputs; }
private:
string word;
std::shared_ptr<set<size_t>> nos;
std::shared_ptr<StrVec> inputs;
};
QueryResult::~QueryResult()
{
}
inline TextQuery::TextQuery(ifstream& ifs) : text(new StrVec, DebugDelete("TextQuery::StrVec")), query_words(new map<string, std::shared_ptr<set<size_t>>>, DebugDelete("TextQuery::map<string, std::shared_ptr<set<size_t>>>"))
{
size_t size = 0;
if (ifs) {
for (string line; getline(ifs, line, '.'); ++size)
{
text->push_back(line);
istringstream iss(line);
size = text->size();
for (string text, word; iss >> text; word.clear()) {
std::remove_copy_if(text.begin(), text.end(),
std::back_inserter(word), ispunct);
// use reference avoid count of shared_ptr add.
auto& nos = (*query_words)[word];
if (!nos) nos.reset(new std::set<size_t>);
nos->insert(size);
}
}
}
}
inline QueryResult TextQuery::query(string s) const {
static std::shared_ptr<std::set<size_t>> nodate(new std::set<size_t>, DebugDelete("TextQuery::std::set<size_t>"));
auto found = query_words->find(s);
if (found == query_words->end()) {
cout << s + " is not in the text" << endl;
return QueryResult(s, nodate, text);
}
else
return QueryResult(s, found->second, text);
}
TextQuery::~TextQuery()
{
}
std::ostream& print(std::ostream& os, const QueryResult qr) {
os << qr.word << " occurs " << qr.nos->size() << " times" << endl;
for (auto i : *qr.nos) {
os << "\t(line " << i + 1 << ") " << qr.inputs->at(i) << std::endl;
}
return os;
}
}
#endif // !TEXTQUERT_H_
#ifndef _QUERY_H_
#define _QUERY_H_
#include "TextQuery.h"
namespace chapter15
{
class Query_base
{
friend class Query;
protected:
virtual ~Query_base() = default;
private:
virtual chapter10::QueryResult eval(const chapter10::TextQuery&)const = 0;
virtual std::string rep()const = 0;
};
class Query
{
friend Query operator~(const Query&);
friend Query operator|(const Query&, const Query&);
friend Query operator&(const Query&, const Query&);
public:
Query(const std::string&);
chapter10::QueryResult eval(const chapter10::TextQuery& t)const {
return q->eval(t);
}
std::string rep()const {
std::cout << "QueryResult::rep" << std::endl;
return q->rep();
}
private:
Query(std::shared_ptr<Query_base> query) :q(query) {}
std::shared_ptr<Query_base> q;
};
class WordQuery :public Query_base
{
friend class Query;
WordQuery(const std::string& s) :query_word(s) {
std::cout << "WordQuery::WordQuery" << std::endl;
}
chapter10::QueryResult eval(const chapter10::TextQuery& t)const {
return t.query(query_word);
}
std::string rep()const {
std::cout << "WordQuery::rep" << std::endl;
return query_word;
}
std::string query_word;
};
Query::Query(const std::string& s) :q(new WordQuery(s)) {
std::cout << "Query::Query" << std::endl;
}
class NotQuery :public Query_base
{
friend Query operator~(const Query&);
NotQuery(const Query& q) :query(q) {
std::cout << "NotQuery::NotQuery" << std::endl;
}
std::string rep()const {
std::cout << "NotQuery::rep" << std::endl;
return"~(" + query.rep() + ")";
}
chapter10::QueryResult eval(const chapter10::TextQuery&)const;
Query query;
};
inline Query operator~(const Query& operand)
{
return std::shared_ptr<Query_base>(new NotQuery(operand));
}
chapter10::QueryResult NotQuery::eval(const chapter10::TextQuery& text) const
{
auto result = query.eval(text);
auto ret_lines = std::make_shared<set<size_t>>();
auto beg = result.begin(), end = result.end();
auto sz = result.get_file()->size();
for (size_t n = 0; n != sz; ++n) {
if (beg == end || *beg != n)
ret_lines->insert(n);
else if (beg != end)
++beg;
}
string s = rep();
return chapter10::QueryResult(s, ret_lines, result.get_file());
}
class BinaryQuery :public Query_base
{
protected:
BinaryQuery(const Query& l, const Query& r, std::string s) :lhs(l), rhs(r), opSym(s) {
std::cout << "BinaryQuery::BinaryQuery" << std::endl;
}
std::string rep() const
{
std::cout << "BinaryQuery::rep" << std::endl;
return "(" + lhs.rep() + " " + opSym + " " + rhs.rep() + ")";
}
Query lhs, rhs;
std::string opSym;
};
class AndQuery : public BinaryQuery
{
friend Query operator& (const Query&, const Query&);
AndQuery(const Query& left, const Query& right) : BinaryQuery(left, right, "&") {
std::cout << "AndQuery::AndQuery" << std::endl;
}
chapter10::QueryResult eval(const chapter10::TextQuery&) const;
};
inline Query operator& (const Query& lhs, const Query& rhs)
{
return std::shared_ptr<Query_base>(new AndQuery(lhs, rhs));
}
chapter10::QueryResult AndQuery::eval(const chapter10::TextQuery& text) const
{
auto right = rhs.eval(text), left = lhs.eval(text);
auto ret_lines = std::make_shared<set<size_t>>();
set_intersection(left.begin(), left.end(), right.begin(), right.end(), inserter(*ret_lines, ret_lines->begin()));
string s = rep();
return chapter10::QueryResult(s, ret_lines, left.get_file());
}
class OrQuery : public BinaryQuery
{
friend Query operator| (const Query&, const Query&);
OrQuery(const Query& left, const Query& right) : BinaryQuery(left, right, "|") {
std::cout << "OrQuery::OrQuery" << std::endl;
}
chapter10::QueryResult eval(const chapter10::TextQuery&) const;
};
inline Query operator| (const Query& lhs, const Query& rhs)
{
return std::shared_ptr<Query_base>(new OrQuery(lhs, rhs));
}
chapter10::QueryResult OrQuery::eval(const chapter10::TextQuery& text) const
{
auto right = rhs.eval(text), left = lhs.eval(text);
auto ret_lines = std::make_shared<set<size_t>>(left.begin(), left.end());
ret_lines->insert(right.begin(), right.end());
string s = rep();
return chapter10::QueryResult(s, ret_lines, left.get_file());
}
std::ostream& operator<<(std::ostream& os, const Query& query) {
return os << query.rep();
}
}
#endif // !_QUERY_H_
练习18.13
在文件中使用静态声明的时候使用未命名的命名空间
练习18.14
mathLib::MatrixLib::matrix mathLib::MatrixLib::operator* (const mathLib::MatrixLib::matrix &, const mathLib::MatrixLib::matrix &);
练习18.15
using声明简单地令名字在局部作用域内有效,using指示是令整个命名空间的所有内容变得有效
练习18.16
练习18.17
namespace Exercise {
int ivar = 0;
double dvar = 0;
const int limit = 1000;
}
int ivar = 0;
using Exercise::ivar;//隐藏了全局ivar
using Exercise::dvar;
using Exercise::limit;
void manip() {
double var = 3.1416;
int iobj = limit + 1;
++ivar;
++::ivar;
}
namespace Exercise {
int ivar = 0;
double dvar = 0;
const int limit = 1000;
}
int ivar = 0;
//using Exercise::ivar;//隐藏了全局ivar
//using Exercise::dvar;
//using Exercise::limit;
void manip() {
using namespace Exercise;
double var = 3.1416;
int iobj = limit + 1;
++ivar;//二义性错误:是全局的ivar还是Exercise::ivar
++::ivar;//是全局的ivar
}
练习18.18
当mem1是一个string时程序会优先查找string库使用swap的string版本,当mem1时int时使用std::swap的int版本
练习18.19
直接调用std::swap模版而不会去查找所属的命名空间
练习18.20
候选函数:全部
namespace primerLib
{
void compute() {}//不可行
void compute(const void*) {}//可行,0->NULL
}
using primerLib::compute;
void compute(int) {}//可行,最佳匹配
void compute(double, double = 1.1) {}//可行,int->double
void compute(char*, char* = 0) {}//可行,0->NULL
void f()
{
compute(0);//与compute(int)版本最佳匹配
}<br />
候选函数:primerLib::compute(),primerLib::compute(const void*)
namespace primerLib
{
void compute() {}//不可行
void compute(const void*) {}//可行,0->NULL,最佳匹配
}
using primerLib::compute;
void compute(int) {}//被屏蔽
void compute(double, double = 1.1) {}//被屏蔽
void compute(char*, char* = 0) {}//被屏蔽
void f()
{
compute(0);//与compute(const void*)版本最佳匹配
}
练习18.21
(a) class CADVehicle : public CAD, Vehicle { ... };//公有继承CAD,私有继承Vehicle
(b) class DbiList : public List, public List { ... };//公有继承List,重复继承
(c) class iostream : public istream, public ostream { ... };//公有继承istream,公有继承ostream
练习18.22
((A->B->C)|((X|Y)->Z))->MI
练习18.23
都允许
练习18.24
ZooAnimal *pza=new Panda("Ying_yang");
pza->print();正确
pza->highlight() 错误;
pza->toes() 错误;
pza->duddle() 错误;
delete pza 正确。
练习18.25
Base1 *pb1 = new MI;
Base2 *pb2 = new MI;
D1 *pd1 = new MI;
D2 *pd2 = new MI;
(a) pb1->print();//MI::print()
(b) pd1->print();//MI::print()
(c) pd2->print();//MI::print()
(d) delete pb2;//MI::~MI()
(e) delete pd1;//MI::~MI()
(f) delete pd2;//MI::~MI()
练习18.26
会产生二义性
struct MI : public Derived, public Base2 {
void print(std::vector<double>) {};
void print(int x) {
Base1::print(x);
}
protected:
int* ival;
std::vector<double> dvec;
};
练习18.27
(a)
Base1中,ival、dval、cval、print可见
Base2中,fval、print可见
Derived中,sval、dval、print可见
MI中,ival、dvec、print、foo可见
(b)
存在。
dval:Base1::dval、Derived::dval、int dval
ival :MI::ival、Base1::ival
cval:Base1::cval、形参cval
print:Base1:print、Base2::print、Derived::print、MI::print
(c)
dval=Base1::dval+Derived::dval;
(d)
fval=dvec.back();
(e)
sval[0]=Base1::cval;
练习18.28
bar,ival能直接访问
foo,cval不能直接访问
练习18.29
(a)构造((Class->Base->(D1|D2)->MI)|Class)->Final,析构Final->(Class|(MI->(D1|D2)->Base->Class))
(b)一个Base部分,两个Class部分
(c)
(a)错误,Class是Base的基类,而pb是Base类
(b)正确,基类Class可以指向所有子类
(c)错误、pb是Base类,MI是Base的子类
(d)正确、D2是MI的基类
练习18.30
class Class {
public:
Class(){}
};
class Base : public Class {
public:
Base() :ival(0) {}
Base(const Base& b) {
ival = b.ival;
}
Base(int i) {
ival = i;
}
protected:
int ival;
};
class D1 : virtual public Base {
public:
D1() :Base() {}
D1(const D1& d1) :Base(d1) {}
D1(int i) :Base(ival) {}
};
class D2 : virtual public Base {
public:
D2() :Base() {}
D2(const D1& d1) :Base(d1) {}
D2(int i) :Base(ival) {}
};
class MI : public D1, public D2 {
public:
MI() = default;
MI(const MI& m) :D1(m), D2(m) {}
MI(int i) : D1(i), D2(i) { cout << "MI(int)" << endl; }
};
class Final : public MI, public Class {
public:
Final() = default;
Final(const Final& f) : MI(f), Class() {}
Final(int i) : MI(i), Class() { cout << "MI(int)" << endl; }
};
class Class {
public:
Class(){}
};
class Base : public Class {
public:
Base() :ival(0) {}
Base(const Base& b) {
ival = b.ival;
}
Base(int i) {
ival = i;
}
protected:
int ival;
};
class D1 : virtual public Base {
public:
D1() :Base() {}
D1(const D1& d1) :Base(d1) {}
D1(int i) :Base(ival) {}
};
class D2 : virtual public Base {
public:
D2() :Base() {}
D2(const D1& d1) :Base(d1) {}
D2(int i) :Base(ival) {}
};
class MI : public D1, public D2 {
public:
MI() = default;
MI(const MI& m) :D1(m), D2(m) {}
MI(int i) : D1(i), D2(i) { cout << "MI(int)" << endl; }
};
class Final : public MI, public Class {
public:
Final() = default;
Final(const Final& f) : MI(f), Class() {}
Final(int i) : MI(i), Class() { cout << "MI(int)" << endl; }
};