Exercise 18.1

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// range_error r("error");
// throw r;
// type of exception object: range_error
// exception *p = &r;
// throw *p;
// type of exception object: exception
// the static, compile-time type of that expression determines the type of the exception object.
// 'throw *p' replaced by throw p;
// pointer points to a local object;
// the matched catch expression may use this pointer to access a destructed object, which would casue an error, program terminates.

Exercise 18.2

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
void exercise(int *b, int *e)
{
  vector<int> v(b, e);
  int *p = new int[v.size()];
  ifstream in("this");
  // there exception occurs

  // suspend the process of current function;
  // if there is a matched catch expression in current function
  // execute this expression and program processing from the point
  // which is just after the last catch expression of matched catch
  // expression group;
  // if not so,
  // leave and go on searching for matched catch in caller function
  // local objects defined in this function body would be destructed.
}

Exercise 18.3

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// This exercise is very ambiguous and misleading;
// another solution see https://github.com/Mooophy/Cpp-Primer/blob/master/ch18/ex18.1.2.3.cpp
// 1. associated try-catch expression inside function where exception occurs;
// 2. associated try-catch expression placed in caller function.
void exercise(int *b, int *e)
{
  vector<int> v(b, e);
  int *p = new int[v.size()];
  ifstream in("this");
  // there exception occurs
  // 1.
  // try{...}
  // catch(exception){...}
}
void caller_exercise()
{
  // 2.
  // try{...exercise(...)...}
  // catch(exception){...}
}

Exercise 18.4

1
2
3
4
5
6
// This catch expressions alignment illustrated in section 18.1.2 should be reversed, for that the certain exception object would always match the first catch expression if object's type is derived from exception class.
// try { // C++ stand library }
// catch (overflow_error eobj) { //... }
// catch(const runtime_error &re) { //... }
// catch(exception) { //... }

Exercise 18.5

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
using namespace std;
int main()
{
  try
    {
      // ...
    }
  catch(length_error e)
    {
      cerr << e.what() << endl;
      abort();
    }
  catch(invalid_argument e)
    {
      cerr << e.what() << endl;
      abort();
    }
  catch(out_of_range e)
    {
      cerr << e.what() << endl;
      abort();
    }
  catch(domain_error e)
    {
      cerr << e.what() << endl;
      abort();
    }
  catch(range_error e)
    {
      cerr << e.what() << endl;
      abort();
    }
  catch(underflow_error e)
    {
      cerr << e.what() << endl;
      abort();
    }
  catch(overflow_error e)
    {
      cerr << e.what() << endl;
      abort();
    }
  catch(logic_error e)
    {
      cerr << e.what() << endl;
      abort();
    }
  catch(runtime_error e)
    {
      cerr << e.what() << endl;
      abort();
    }
  catch(bad_cast e)
    {
      cerr << e.what() << endl;
      abort();
    }
  catch(bad_alloc e)
    {
      cerr << e.what() << endl;
      abort();
    }
  catch(exception e)
    {
      cerr << e.what() << endl;
      abort();
    }
}

Exercise 18.6

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// a
// class exceptionType {};
// exceptionType obj;
// try{ throw &obj; }
// catch(execptionType *pet) {}
// b
// try{ throw exception();}
// catch(...) {}
// c
// typedef int EXCPTYPE;
// try{ throw 42;}
// catch(EXCPTYPE) {}

Exercise 18.7

1
2
// See Blob.h.

Blob.h

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
template <typename T> class BlobPtr;
template <typename T> class Blob
{
  friend class BlobPtr<T>;
 public:
  using sh = My_shared_ptr<vector<T>>;
  typedef typename vector<T>::size_type size_type;
  Blob();
  Blob(initializer_list<T> il);
  template <typename It> Blob(It it1, It it2);
  size_type size() const {return data->size();}
  bool empty() const {return data->empty();}
  void push_back(const T &t) {data->push_back(t);}
  void push_back(T &&t) {data->push_back(std::move(t));}
  void pop_back();
  T &front();
  const T &front() const;
  T &back();
  const T &back() const;
  T &operator[](size_type i);
  BlobPtr<T> begin();
  BlobPtr<T> end();
 private:
  sh data;
  void check(size_type i, const string &msg) const;
};
template <typename T> Blob<T>::Blob()
try: data(sh()) {}
catch(const bad_alloc &e) {cerr << e.what() << endl; abort();}
template <typename T> Blob<T>::Blob(initializer_list<T> il)
try: data(sh(il)) {}
catch(const bad_alloc &e) {cerr << e.what() << endl; abort();}
template <typename T>
template <typename It>
Blob<T>::Blob(It it1, It it2): data(sh(it1, it2)) {}
template <typename T> void Blob<T>::check(size_type i, const string &msg) const
{
  if(i >= data->size())
    throw out_of_range(msg);
}
template <typename T> T& Blob<T>::front()
{
  check(0, "front on empty Blob");
  return data->front();
}
template <typename T> const T &Blob<T>::front() const
{
  check(0, "front on empty Blob");
  return data->front();
}
template <typename T> T &Blob<T>::back()
{
  check(0, "badk on empty Blob");
  return data->back();
}
template <typename T> const T &Blob<T>::back() const
{
  check(0, "back on empty Blob");
  return data->back();
}
template <typename T> T &Blob<T>::operator[](size_type i)
{
  check(i, "subscript out of range");
  return (*data)[i];
}
template <typename T> bool operator==(const BlobPtr<T> &a, const BlobPtr<T> &b)
{
  if(a.wptr.lock() == b.wptr.lock())
    {
      throw runtime_error("ptrs to different Blobs!");
    }
  return a.curr == b.curr;
}
template <typename T> bool operator< (const BlobPtr<T> &a, const BlobPtr<T> &b)
{
  if(a.wptr.lock() != b.wptr.lock())
    {
      throw runtime_error("ptrs to different Blobs!");
    }
  return a.curr < b.curr;
}
template <typename T> class BlobPtr
{
  friend bool operator==<T>(const BlobPtr<T> &, const BlobPtr<T> &);
  friend bool operator< <T>
    (const BlobPtr<T> &, const BlobPtr<T> &);
 public:
 BlobPtr(): curr(0) {}
 BlobPtr(Blob<T> &a, size_t sz = 0): wptr(a.data), curr(sz) {}
  T &operator*() const
    {
      auto p = check(curr, "dereference past end");
      return (*p)[curr];
    }
  BlobPtr &operator++();
  BlobPtr &operator--();
 private:
  My_shared_ptr<vector<T>> check(size_t,const string&) const;
  weak_ptr<vector<T>> wptr;
  size_t curr;
};
template <typename T>
BlobPtr<T> &BlobPtr<T>::operator++()
{
  check(curr, "increment past end of StrBlobPtr");
  ++curr;
  return *this;
}
template <typename T>
BlobPtr<T> &BlobPtr<T>::operator--()
{
  --curr;
  check(curr, "increment past end of StrBlobPtr");
  return *this;
}
template <typename T> My_shared_ptr<vector<T>> BlobPtr<T>::check(size_t i, const string &msg) const
{
  auto ret = wptr.lock();
  if(!ret)
    throw runtime_error("unbound BlobPtr");
  if(i >= ret->size())
    throw out_of_range(msg);
  return ret;
}

Exercise 18.8

1
2
3
4
5
// Again ambiguous and misleading;
// Too much workd and not necessary;
// Ensure that every function and operation called in one destructor must be noexcept, then this destructor is noexcept;
// or that could not be guaranteed, use function try block in destructor to handle exceptions.

Exercise 18.9

1
2
// See Sales_data_exception.h, Sales_data.h and Sales_data.cpp.

Sales_data.cpp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
Sales_data& Sales_data::combine(const Sales_data &rhs)
{
  units_sold += rhs.units_sold;
  revenue += rhs.revenue;
  return *this;
}
inline double Sales_data::avg_price() const
{
  if(units_sold)
    return revenue/units_sold;
  else
    return 0;
}
istream &read(istream &is, Sales_data &item)
{
  double price;
  is >> item.bookNo >> item.units_sold >> price;
  if(is)
    item.revenue = price * item.units_sold;
  else
    item = Sales_data();
  return is;
}
istream &operator>>(istream &i, Sales_data &data)
{
  double price;
  i >> data.bookNo >> data.units_sold >> price;
  if(i)
    data.revenue = price * data.units_sold;
  else
    data = Sales_data();
  return i;
}
ostream &print(ostream &os, const Sales_data &item)
{
  os << item.isbn() << " " << item.units_sold << " " << item.revenue << " " << item.avg_price();
  return os;
}
ostream &operator<<(ostream &o, const Sales_data &data)
{
  o << data.isbn() << " " << data.units_sold << " " << data.revenue << " " << data.avg_price();
  return o;
}
Sales_data add(const Sales_data &item1, const Sales_data &item2)
{
  Sales_data result = item1;
  return result.combine(item2);
}
Sales_data &Sales_data::operator+=(const Sales_data &data)
{
  if(isbn() != data.isbn())
    throw isbn_mismatch("wrong  isbns", isbn(), data.isbn());
  return combine(data);
}
Sales_data &Sales_data::operator-=(const Sales_data &data)
{
  units_sold -= data.units_sold;
  revenue -= data.revenue;
  return *this;
}
Sales_data &Sales_data::operator=(const string &s)
{
  bookNo = s;
  units_sold = 0;
  revenue = 0.0;
  return *this;
}
Sales_data operator+(const Sales_data &data1, const Sales_data &data2)
{
  Sales_data temp = data1;
  temp += data2;
  return temp;
}
Sales_data operator-(const Sales_data &data1, const Sales_data &data2)
{
  Sales_data temp = data1;
  temp -= data2;
  return temp;
}
bool operator==(const Sales_data &data1, const Sales_data &data2)
{
  return data1.bookNo == data2.bookNo &&
    data1.units_sold == data2.units_sold &&
    data1.revenue == data2.revenue;
}
bool operator!=(const Sales_data &data1, const Sales_data &data2)
{
  return !(data1 == data2);
}

Sales_data.h

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#ifndef SALES_DATA_H
#define SALES_DATA_H
struct Sales_data;
istream &read(istream &is, Sales_data &item);
ostream &print(ostream &os, const Sales_data &item);
Sales_data add(const Sales_data &item1, const Sales_data &item2);
struct Sales_data {
  friend istream &read(istream &, Sales_data &);
  friend ostream &print(ostream &, const Sales_data &);
  friend Sales_data add(const Sales_data &item1, const Sales_data &item2);
  friend Sales_data operator+(const Sales_data &, const Sales_data &);
  friend istream &operator>>(istream &, Sales_data &);
  friend ostream &operator<<(ostream &, const Sales_data &);
  friend bool operator==(const Sales_data &, const Sales_data &);
  friend bool operator!=(const Sales_data &, const Sales_data &);
  friend Sales_data operator-(const Sales_data &, const Sales_data &);
public:
  // Sales_data(): bookNo(""), units_sold(0), revenue(0) {}
  // Exercise 7.14 above has misleading due to the CN version.
  // It's ok to use the in-class initializer values.
Sales_data(): Sales_data("", 0, 0)
  {cout << " Default";};
Sales_data(const string &s): Sales_data(s, 0, 0)
  {cout << " With string argument";}
Sales_data(const string &s, unsigned n, double p):
  bookNo(s), units_sold(n), revenue(p*n)
  {cout << " With three arguments";}
Sales_data(istream &is): Sales_data()
  {cout << " With istream argument"; read(is, *this);}
  string isbn() const {return bookNo;}
  Sales_data& combine(const Sales_data&);
  Sales_data &operator+=(const Sales_data &);
  Sales_data &operator-=(const Sales_data &);
  Sales_data &operator=(const string &);
  operator string() const {return bookNo;}
  operator double() const {return revenue;}
private:
  double avg_price() const;
  string bookNo;
  unsigned units_sold = 0;
  double revenue = 0.0;
};
#endif

Sales_data_exception.h

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#ifndef SALES_DATA_EXCEPTION
#define SALES_DATA_EXCEPTION
class out_of_stock: public runtime_error
{
 public:
  explicit out_of_stock(const string &s): runtime_error(s) {}
};
class isbn_mismatch: public logic_error
{
 public:
  explicit isbn_mismatch(const string &s):
  logic_error(s) {}
 isbn_mismatch(const string &s, const string &lhs, const string &rhs):
  logic_error(s), left(lhs), right(rhs) {}
  string left, right;
};
#endif

Exercise 18.10

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int main()
{
  Sales_data item1, item2, sum;
  while(cin >> item1 >> item2)
    sum = item1 + item2;
  // just like said in section 18.1.1
  // for on throwed exception, if there is no matched catch expression
  // program calls std library function terminate to terminate program processing
}
// int main()
// {
//   Sales_data item1, item2, sum;
//   while(cin >> item1 >> item2)
//     {
//       try
// 	{
// 	  sum = item1 + item2;
// 	}
//       catch(const isbn_mismatch &e)
// 	{
// 	  cerr << e.what() << ": left isbn(" << e.left
// 	       << ") right isbn(" << e.right << ")" << endl;
// 	}
//     }
// }

Exercise 18.11

1
2
// During handle process of exception, there should not have another exception again, or std library function terminate is called to terminate the program processing.

Exercise 18.12

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// See chapter15.h, chapter10.h.
int main(int argc, char *argv[])
{
  ifstream ifs(argv[1]);
  chapter10::TextQuery tq(ifs);
  chapter15::Query q = chapter15::Query("fiery") & chapter15::Query("bird") | chapter15::Query("wind");
  cout << q << endl;
  auto result = q.eval(tq);
  print(cout, result);
}

chapter10.h

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#ifndef CHAPTER10_H
#define CHAPTER10_H
namespace chapter10{
  class QueryResult;
  class TextQuery
  {
  public:
    using line_no = vector<string>::size_type;
    TextQuery(ifstream &infile);
    TextQuery(const TextQuery &);
    TextQuery &operator=(const TextQuery &);
    QueryResult query(const string &s) const;
  private:
    friend QueryResult;
    shared_ptr<vector<string>> sp1;
    map<string, shared_ptr<set<line_no>>> mp;
  };
  TextQuery::TextQuery(ifstream &infile):
  sp1(new vector<string>)
    {
      line_no line_number = 0;
      string line;
      while(getline(infile, line))
      {
	// store line in vector<string>
	sp1->push_back(line);
	// scan through the line
	istringstream ist(line);
	string word;
	while(ist >> word)
	  {
	    if(ispunct(word[word.size() - 1]))
	      word.erase(word.size() - 1);
	    auto &lines = mp[word];
	    if(!lines) lines.reset(new set<line_no>);
	    lines->insert(line_number);
	  }
	// increase the line_number
	++line_number;
      }
    }
  TextQuery::TextQuery(const TextQuery &t): sp1(make_shared<vector<string>>(*t.sp1)), mp(t.mp) {}
  TextQuery &TextQuery::operator=(const TextQuery &t)
    {
      sp1 = make_shared<vector<string>>(*t.sp1);
      mp = t.mp;
      return *this;
    }
  class QueryResult
  {
    friend ostream &print(ostream &, const QueryResult &);
    string search_word;
    shared_ptr<vector<string>> sp1;
    shared_ptr<set<TextQuery::line_no>> sp2;
  public:
  QueryResult(const string &s,
	    shared_ptr<set<TextQuery::line_no>> p,
	    shared_ptr<vector<string>> file): search_word(s), sp1(file), sp2(p) {}
    QueryResult(const QueryResult &);
    QueryResult &operator=(const QueryResult &);
    set<TextQuery::line_no>::iterator begin() {return sp2->begin();}
    set<TextQuery::line_no>::iterator end() {return sp2->end();}
    shared_ptr<vector<string>> get_file() {return sp1;}
  };
  QueryResult::QueryResult(const QueryResult &q): sp1(make_shared<vector<string>>(*q.sp1)), sp2(make_shared<set<TextQuery::line_no>>(*q.sp2)), search_word(q.search_word) {}
  QueryResult &QueryResult::operator=(const QueryResult &q)
    {
      sp1 = make_shared<vector<string>>(*q.sp1);
      sp2 = make_shared<set<TextQuery::line_no>>(*q.sp2);
      search_word = q.search_word;
      return *this;
    }
  ostream &print(ostream &o, const QueryResult &q)
    {
      auto n = q.sp2->size();
      o << "element occurs " << n << " times" << endl;
      auto result = *q.sp2;
      for(const auto &l : result)
      cout << "\t(line " << l + 1 << ") "
	   << (*q.sp1)[l] << endl;
      return o;
    }
  QueryResult TextQuery::query(const string &s) const
  {
    static shared_ptr<set<line_no>> nodata(new set<line_no>);
    auto iter = mp.find(s);
    auto last = mp.end();
    if(iter != last)
      return QueryResult(s, iter->second, sp1);
    else
      return QueryResult(s, nodata, sp1);
  }
}
#endif

chapter15.h

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#ifndef CHAPTER15_H
#define CHAPTER15_H
namespace chapter15
{
  class Query_base
  {
    friend class Query;
  protected:
    using line_no = chapter10::TextQuery::line_no;
    Query_base() {}
    virtual ~Query_base() = default;
  private:
    virtual chapter10::QueryResult eval(const chapter10::TextQuery &) const = 0;
    virtual 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 string &);
  Query(const Query &p): q(p.q), use(p.use) {++*use;}
    Query &operator=(const Query &p);
    chapter10::QueryResult eval(const chapter10::TextQuery &t) const {return q->eval(t);}
    string rep() const {return q->rep();}
    ~Query()
      {
      if(--*use == 0)
	{
	  delete q;
	  delete use;
	}
      }
  private:
  Query(Query_base *query): q(query), use(new unsigned(1)) {}
    Query_base *q;
    unsigned *use;
  };
  Query &Query::operator=(const Query &p)
    {
      ++*p.use;
      if(--*use == 0)
      {
	delete use;
	delete q;
      }
      use = p.use;
      q = p.q;
      return *this;
    }
  class WordQuery: public Query_base
  {
    friend class Query;
  WordQuery(const string &s): query_word(s) {}
    chapter10::QueryResult eval(const chapter10::TextQuery &t) const
    {return t.query(query_word);}
    string rep() const {return query_word;}
    string query_word;
  };
  inline Query::Query(const string &s): q(new WordQuery(s)), use(new unsigned(1)) {}
  class BinaryQuery: public Query_base
  {
  protected:
  BinaryQuery(const Query &l, const Query &r, string s):
    lhs(l), rhs(r), opSym(s) {}
    string rep() const
    {
      return "(" + lhs.rep() + " "
      + opSym + " "
      + rhs.rep() + ")";
    }
    Query lhs, rhs;
    string opSym;
  };
  class AndQuery: public BinaryQuery
  {
    friend Query operator&(const Query &, const Query &);
  AndQuery(const Query &left, const Query &right):
    BinaryQuery(left, right, "&") {}
    chapter10::QueryResult eval(const chapter10::TextQuery &) const;
  };
  inline Query operator&(const Query &lhs, const Query &rhs)
  {
    return new AndQuery(lhs, rhs);
  }
  chapter10::QueryResult
    AndQuery::eval(const chapter10::TextQuery &text) const
  {
    auto left = lhs.eval(text), right = rhs.eval(text);
    auto ret_lines = make_shared<set<line_no>>();
    set_intersection(left.begin(), left.end(),
		   right.begin(), right.end(),
		   inserter(*ret_lines, ret_lines->begin()));
    return chapter10::QueryResult(rep(), 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, "|") {}
    chapter10::QueryResult eval(const chapter10::TextQuery &) const;
  };
  inline Query operator|(const Query &lhs, const Query &rhs)
  {
    return new OrQuery(lhs, rhs);
  }
  ostream &operator<<(ostream &os, const Query &query)
    {
      return os << query.rep();
    }
  chapter10::QueryResult OrQuery::eval(const chapter10::TextQuery &text) const
  {
    auto right = rhs.eval(text), left = lhs.eval(text);
    auto ret_lines = make_shared<set<line_no>>(left.begin(), left.end());
    ret_lines->insert(right.begin(), right.end());
    return chapter10::QueryResult(rep(), ret_lines, left.get_file());
  }
  class NotQuery: public Query_base
  {
    friend Query operator~(const Query &);
  NotQuery(const Query &q): query(q) {}
    string rep() const {return "~(" + query.rep() + ")";}
    chapter10::QueryResult eval(const chapter10::TextQuery &) const;
    Query query;
  };
  inline Query operator~(const Query &operand)
  {
    return new NotQuery(operand);
  }
  chapter10::QueryResult
    NotQuery::eval(const chapter10::TextQuery &text) const
  {
    auto result = query.eval(text);
    auto ret_lines = make_shared<set<line_no>>();
    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;
      }
    return chapter10::QueryResult(rep(), ret_lines, result.get_file());
  }
}
#endif

Exercise 18.13

1
2
// When there is a need to define a name which is visible and accessible in current file, but not so for external files.

Exercise 18.14

1
2
// mathLib::MatrixLib::matrix mathLib::MatrixLib::operator*(const matrix &, const matrix &);

Exercise 18.15

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// using declaration
// introduces one member of specified namespace at one time;
// could put in global scope, local scope, namespace scope and class scope;
// name conflict bug easy to find and correct;
// usiing directive
// make all names of specified namespace visible and accessible;
// could put in global scope, local scope and namespace scope, but not class scope;
// more complicated mechanism, it lifts namespace members to the most close outer scope which includes namesapce itself and using directive;
// more likely to bring name conflict issue, bug hard to find and correct;

Exercise 18.16

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// position 1 replaced by using declarations of all Exercise namespace members;
// would bring name conflict of variable ivar defined in global scope and variable ivar defined in namespace Exercise;
// this bug could be found out at the ivar using declaration;
// position 2
// name conflict of variable dvar defined in local scope and variable dvar defined in namespace Exercise;
// this bug could be found out at the definition of local variable dvar;
// position 1 replaced by using directive of namespace Exercise;
// name conflict same as the first situation;
// while this bug would not be found out until the '++ivar;' expression inside function manip;
// position 2
// same as the above one.

Exercise 18.17

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
namespace Exercise
{
  int ivar = 0;
  double dvar = 0;
  const int limit = 1000;
}
int ivar = 0;
// using Exercise::ivar;    // name conflict
// using Exercise::dvar;
// using Exercise::limit;
// using namespace Exercise;
void manip()
{
  // using Exercise::ivar;
  // using Exercise::dvar;
  // using Exercise::limit;
  // using namespace Exercise;

  double dvar = 3.1416;
  // would bring name conflict if there are using declarations of all members of namespace Exercise inside manip;
  int lobj = limit + 1;
  ++ivar;			// using directive: ambiguous: which ivar?
  ++::ivar;
}

Exercise 18.18

1
2
// This I really do not know, still section 18.2.3 has not explained clearly about what is the mechanism of std::swap.

Exercise 18.19

1
2
3
// std::swap(v1.mem1, v2,mem1);
// would use the matching std version of swap(for string type) for that specified call.

Exercise 18.20

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
namespace primerLib
{
  void compute();		// 1
  void compute(const void *);	// 2
}
using primerLib::compute;
void compute(int);		// 3
void compute(double, double = 3.4); // 4
void compute(char *, char * = 0);   // 5
void f()
{
  compute(0);
}
// first question:
// finally call version 3;
// candidate functions:
// 1
// 2
// 3
// 4
// 5
// workable functions:
// 2, literal constant 0 converted to const void *
// 3, match
// 4, int converted to double
// 5, literal constant 0 conveted to char *;
// second question:
// hide the function declarations with same name in outer scope;
// finally call version 2;
// candidate functions:
// 1
// 2
// workable functions:
// 2, literal constant 0 converted to const void *

Exercise 18.21

1
2
3
4
5
// a: class CADVehicle pubicly derived from class CAD and privately derived from class Vehicle;
// b: illegal;
// one base class only occurs one time in one given derived list;
// c: class iostream publicly derived from class istream and alos publicly derived from class ostream;

Exercise 18.22

1
2
// A, B, C, X, Y, Z, MI.

Exercise 18.23

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// class D: public X, public C { ... };
// D *pd = new D;
// X *px = pd;
// legal;
// A *pa = pd;
// legal;
// B *pb = pd;
// legal;
// C *pc = pd;
// legal;

Exercise 18.24

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// ZooAnimal *pz = new Panda("ying_yang");
// pz->print();
// Panda::print();
// pz->cuddle();
// illegal, interface not belong to class ZooAnimal;
// pz->highlight();
// illegal, ingerface not belong to class ZooAnimal;
// delete pz;
// Panda::~Panda();

Exercise 18.25

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// class D1: public Base1 { /*...*/ };
// class D2: public Base2 { /*...*/ };
// class MI: public D1, public D2 { /*...*/ };
// 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():
// D2::~D2();
// Base2::~Base2();
// D1::~D1();
// Base1::~Base1();
// (e) delete pd1;
// same as the former one;
// (f) delete pd2;
// same as the former one;

Exercise 18.26

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
struct Base1
{
  void print(int) const;
protected:
  int ival;
  double dval;
  char cval;
private:
  int *id;
};
struct Base2
{
  void print(double) const;
protected:
  double fval;
private:
  double dval;
};
struct Derived: public Base1
{
  void print(string) const;
protected:
  string sval;
  double dval;
};
struct MI: public Derived, public Base2
{
  void print(vector<double>);
  void print(int i) {Base1::print(i);} // add this
protected:
  int *ival;
  vector<double> dvec;
};
int main()
{
  MI mi;
  mi.print(42);
  // for original classes, this expression would try to call MI::print(vector<double>), while literal int 42 could not be converted to such a type, which would fail in type check and causes a error.
}

Exercise 18.27

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
struct Base1
{
  void print(int) const;
protected:
  int ival;
  double dval;
  char cval;
private:
  int *id;
};
struct Base2
{
  void print(double) const;
protected:
  double fval;
private:
  double dval;
};
struct Derived: public Base1
{
  void print(string) const;
protected:
  string sval;
  double dval;
};
struct MI: public Derived, public Base2
{
  void print(vector<double>);
  void print(int i) {Base1::print(i);}
  void foo(double);
protected:
  int *ival;
  vector<double> dvec;
};
int ival;
double dval;
void MI::foo(double cval)
{
  int dval;
}
// (a):
// ::ival, ::dval;
// MI::ival, MI::dvec, MI::print(vector<double>), MI::print(int);
// Derived::print(string), Derived::sval, Derived::dval;
// Base2::print(double), Base2::fval;
// Base1::print(int), Base1::ival, Base1::dval, Base1::cval;
// (b):
// print
// (c)
// dval = Base1::dval + Derived::dval;
// (d)
// Base2::fval = *dvec.rbegin();
// (e)
// Derived::sval[0] = Base1::cval;

Exercise 18.28

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
struct Base
{
  void bar(int);
protected:
  int ival;
};
struct Derived1: virtual public Base
{
  void bar(char);
  void foo(char);
protected:
  char cval;
};
struct Derived2: virtual public Base
{
  void foo(int);
protected:
  int ival;
  char cval;
};
class VMI: public Derived1, public Derived2 {};
// without specifier:
// bar(Base);
// not defined with int type parameter anywhere;
// bar(Derived1), ival(Derived2);
// appears in one inheritance tree and hides the member with same name in base class;
// with specifier:
// Derived1::foo, Derived1:cval, Derived2::foo, Derived2::cval, Base::ival;
// appears in both inheritance trees, ambiguous problem.

Exercise 18.29

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// class Class { ... };
// class Base: public Class { ... };
// class D1: virtual public Base { ... };
// class D2: virtual public Base { ... };
// class MI: public D1, public D2 { ... };
// class Final: public MI, public Class { ... };
// (a)
// Class();
// Base();
// D1();
// D2();
// MI();
// Class();
// Final();
// and Destructors run order reversed from the formerf one.
// (b)
// one Base sub object, two Class sub objects;
// (c)
// Base *pb;
// Class *pc;
// Mi *pmi;
// D2 *pd2;
// 1. pb = new Class;
// illegal, Base class pointer could not be implicitly converted to its derived class pointer;
// 2. pc = new Final;
// illegal, ambiguous, which Calss sub object?
// 3. pmi = pb;
// illegal, same as 1;
// 4. pd2 = pmil
// legal;

Exercise 18.30

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Class
{};
class Base
{
  int i = 0;
public:
  Base() = default;
  Base(int j): i(j) {}
  Base(const Base &b): i(b.i) {}
};
class D1: virtual public Base
{
public:
  D1(): Base() {}
  D1(int j): Base(j) {}
  D1(const D1 &d): Base(d) {}
};
class D2: virtual public Base
{
public:
  D2(): Base() {}
  D2(int j): Base(j) {}
  D2(const D2 &d): Base(d) {}
};
class MI: public D1, public D2
{
public:
  MI(): Base(), D1(), D2() {}
  MI(int j): Base(j), D1(j), D2(j) {}
  MI(const MI &m): Base(m), D1(m), D2(m) {}
};
class Final: public MI, public Class
{
public:
  Final(): Base(), MI(), Class() {}
  Final(int j): Base(j), MI(j) {}
  Final(const Final &f): Base(f), MI(f) {}
};