C++ Primer第5版 第十八章课后练习答案

练习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; }
};

 

上一篇:《C primer plus》第十章


下一篇:温习C++ Primer【一】