练习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)版本最佳匹配 }
候选函数: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; } };