Exercise 19.1

1
2
3
4
5
6
7
8
9
void *operator new(size_t size)
{
  if(void *mem = malloc(size))
    return mem;
  else
    throw bad_alloc();
}
void operator delete(void *mem) noexcept {free(mem);}

Exercise 19.2

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// See StrVec.h and StrVec.cpp.
void *operator new(size_t size)
{
  cout << "operator new" << endl;
  if(void *mem = malloc(size))
    return mem;
  else
    throw bad_alloc();
}
void operator delete(void *mem) noexcept
{
  cout << "operator delete" << endl;
  free(mem);
}
int main()
{
  StrVec({"hello", "world"});
}

StrVec.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
 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
void StrVec::push_back(const string &s)
{
  chk_n_alloc();
  alloc.construct(first_free++, s);
}
pair<string *, string *>
  StrVec::alloc_n_copy(const string *b, const string *e)
{
  auto data = alloc.allocate(e - b);
  return {data, uninitialized_copy(b, e, data)};
}
void StrVec::free()
{
  if(elements)
    {
      for(auto p = first_free; p != elements;)
      alloc.destroy(--p);
      alloc.deallocate(elements, cap - elements);
    }
  /* for_each(elements, first_free, [this] (string &s) {alloc.destroy(&s);}); */
  /* alloc.deallocate(elements, cap - elements); */
}
StrVec::StrVec(const StrVec &s)
{
  auto newdata = alloc_n_copy(s.begin(), s.end());
  elements = newdata.first;
  first_free = cap = newdata.second;
}
StrVec::StrVec(StrVec &&s) noexcept: first_free(s.first_free), elements(s.elements), cap(s.cap)
{
  s.first_free = nullptr;
  s.elements = nullptr;
  s.cap = nullptr;
}
StrVec::StrVec(const initializer_list<string> &is)
{
  auto newdata = alloc_n_copy(is.begin(), is.end());
  elements = newdata.first;
  first_free = cap = newdata.second;
}
StrVec::~StrVec() {free();}
StrVec &StrVec::operator=(const StrVec &rhs)
{
  auto data = alloc_n_copy(rhs.begin(), rhs.end());
  free();
  elements = data.first;
  first_free = cap = data.second;
  return *this;
}
  string &StrVec::operator[](size_t n)
  {
    if(n >= size())
      throw runtime_error("Out of range");
    else
      return *(elements + n);
  }
const string &StrVec::operator[](size_t n) const
{
  if(n >= size())
    throw runtime_error("Out of range");
  else
    return elements[n];
}
StrVec &StrVec::operator=(StrVec &&s) noexcept
{
  if(&s != this)
    {
      free();
      first_free = s.first_free;
      elements = s.elements;
      cap = s.cap;
      s.first_free = s.elements = s.cap = nullptr;
    }
  return *this;
}
  StrVec &StrVec::operator=(const initializer_list<string> &il)
  {
    auto data = alloc_n_copy(il.begin(), il.end());
    free();
    elements = data.first;
    first_free = cap = data.second;
    return *this;
  }

  void StrVec::reallocate(size_t n)
  {
    auto newcapacity = n ? n : (size() ? 2 * size() : 1);
    auto newdata = alloc.allocate(newcapacity);
    auto dest = newdata;
    auto elem = elements;
    for(size_t i = 0; i != size(); ++i)
      alloc.construct(dest++, std::move(*elem++));
    free();
    elements = newdata;
    first_free = dest;
    cap = elements + newcapacity;
  }
void StrVec::reserve(size_t n)
{
  if(n > capacity())
    reallocate(n);
}
void StrVec::resize(size_t n, string s)
{
  if(n > size() && n <= capacity())
    {
      uninitialized_fill(first_free, elements + n, s);
      first_free = elements + n;
    }
  else if(n > size() && n > capacity())
    {
      reallocate();
      uninitialized_fill(first_free, elements + n, s);
      first_free = elements + n;
    }
  else if(n < size())
    {
      for(auto p = first_free; p != elements + n;)
      alloc.destroy(--p);
    }
}
bool operator==(const StrVec &s1, const StrVec &s2)
{
  vector<string> temp1(s1.begin(), s1.end());
  vector<string> temp2(s2.begin(), s2.end());
  return temp1 == temp2;
}
bool operator!=(const StrVec &s1, const StrVec &s2)
{
  return !(s1 == s2);
}
bool operator<(const StrVec &s1, const StrVec &s2)
{
  vector<string> temp1(s1.begin(), s1.end());
  vector<string> temp2(s2.begin(), s2.end());
  return temp1 < temp2;
}

StrVec.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
#ifndef STRVEC_H
#define STRVEC_H
class StrVec
{
  friend bool operator==(const StrVec &, const StrVec &);
  friend bool operator!=(const StrVec &, const StrVec &);
  friend bool operator<(const StrVec &, const StrVec &);
 public:
 StrVec(): elements(nullptr), first_free(nullptr), cap(nullptr) {}
  StrVec(const StrVec &);
  StrVec(StrVec &&) noexcept;
  StrVec(const initializer_list<string> &is);
  StrVec &operator=(const StrVec &);
  StrVec &operator=(StrVec &&) noexcept;
  StrVec &operator=(const initializer_list<string> &);
  string &operator[](size_t n);
  const string &operator[](size_t n) const;
  ~StrVec();
  void push_back(const string &);
  size_t size() const {return first_free - elements;}
  size_t capacity() const {return cap - elements;}
  void reserve(size_t);
  void resize(size_t n, string s = "");
  string *begin() const {return elements;}
  string *end() const {return first_free;}
 private:
  allocator<string> alloc; /* it using static, 'undefined reference' reported when compile */
  void chk_n_alloc()
  {if(size() == capacity()) reallocate();}
  pair<string *, string *> alloc_n_copy
    (const string *, const string *);
  void free();
  void reallocate(size_t n = 0);
  string *elements;
  string *first_free;
  string *cap;
};
#endif

Exercise 19.3

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// class A { /* ... */ }
// class B: public A { /* ... */ }
// class C: public B { /* ... */ }
// class D: public B, public A { /* ... */ }
// a
// A *pa = new C;
// B *pb = dynamic_cast<B*>(pa);
// legal;
// b
// B *pb = new B;
// C *pc = dynamic_cast<C*>(pb);
// illegal;
// c
// A *pa = new D;
// this would cause ambiguous error, for D class type object contains two A class type sub-objects, so here a error occurs...
// illegal;
// B *pb = dynamic_cast<B*>(pa);

Exercise 19.4

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
////////////////////////////////////////
// try				      //
//   {				      //
//     C &rc = dynamic_cast<C&>(*pa); //
//     // usage of member of C	      //
//   }				      //
//catch(bad_cast)		      //
//   {				      //
//     // usage of member of A	      //
//   }				      //
////////////////////////////////////////

Exercise 19.5

1
2
// When want to use dynamic type object's non-virtual members.

Exercise 19.6

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// Exercise should indicate that there is need to modify the header file contains class Query_base and AndQuery.
int main()
{
  AndQuery aq = AndQuery(Query("hello"), Query("world"));
  OrQuery oq = OrQuery(Query("hello"), Query("world"));
  Query_base *qb1 = &aq;
  Query_base *qb2 = &oq;
  AndQuery *pa1 = dynamic_cast<AndQuery*>(qb1);
  AndQuery *pa2 = dynamic_cast<AndQuery*>(qb2);
  if(pa1 && typeid(*pa1) == typeid(AndQuery))
    cout << "ok" << endl;
  if(pa2 && typeid(*pa2) == typeid(AndQuery))
    cout << "ok" << endl;
}

Exercise 19.7

 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
int main()
{
  AndQuery aq = AndQuery(Query("hello"), Query("world"));
  OrQuery oq = OrQuery(Query("hello"), Query("world"));
  Query_base &qb1 = aq;
  Query_base &qb2 = oq;
  try
    {
      AndQuery &pa1 = dynamic_cast<AndQuery&>(qb1);
      if(typeid(pa1) == typeid(AndQuery))
      cout << "ok" << endl;
    }
  catch(bad_cast)
    {
      cout << "fail" << endl;
    }

  try
    {
      AndQuery &pa2 = dynamic_cast<AndQuery&>(qb2);
      if(typeid(pa2) == typeid(AndQuery))
      cout << "ok" << endl;
    }
  catch(bad_cast)
    {
      cout << "fail" << endl;
    }
}

Exercise 19.8

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
int main()
{
  AndQuery aq = AndQuery(Query("hello"), Query("world"));
  OrQuery oq = OrQuery(Query("hello"), Query("world"));
  Query_base *qb1 = &aq;
  Query_base *qb2 = &oq;
  if(typeid(*qb1) == typeid(*qb2))
    cout << "equal" << endl;
  if(typeid(*qb1) == typeid(AndQuery) || typeid(*qb2) == typeid(AndQuery))
    cout << "AndQuery ok" << endl;
}

Exercise 19.9

 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
struct Base {virtual ~Base() {}};
struct Derived: public Base {};
string name_transfer(const string &s)
{
  string result;
  if(s == "i")
    result = "int";
  else if(s == "A10_i")
    result = "int array[10]";
  else if(s == "NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE")
    result = "string";
  else if(s == "P4Base")
    result = "Base*";
  else if(s == "7Derived")
    result = "Derived";
  return result;
}
int main()
{
  int arr[10];
  Derived d;
  Base *p = &d;
  cout << name_transfer(typeid(42).name()) << ", "
       << name_transfer(typeid(arr).name()) << ", "
       << name_transfer(typeid(string).name()) << ", "
       << name_transfer(typeid(p).name()) << ", "
       << name_transfer(typeid(*p).name()) << endl;
}

Exercise 19.10

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class A
{
public:
  virtual ~A() {}
};
class B: public A {};
class C: public B {};
int main()
{
  A *pa = new C;
  cout << typeid(pa).name() << endl; // A*
  C cobj;
  A &ra = cobj;
  cout << typeid(&ra).name() << endl; // A*
  B *px = new B;
  A &ra2 = *px;
  cout << typeid(ra2).name() << endl; // B
}

Exercise 19.11

1
2
3
// pointer points to data member contains information of the class type the member belongs to;
// and the form of declaration, definition, initialization and usage of that kind of pointer are different from normal pointer.

Exercise 19.12

1
2
3
4
5
6
7
8
9
int main()
{
  Screen s;
  const Screen::pos Screen::*p;
  // Move data member cusrsro to public member to simplify code
  p = &Screen::cursor;
  cout << s.*p << endl;
}

Exercise 19.13

1
2
3
4
5
6
7
8
// See a friend class BookNoPtr of class Sales_data in Sales_data.h.
int main()
{
  Sales_data s("hello");
  BookNoPtr p;
  cout << s.*(p.data()) << endl;;
}

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
45
46
47
48
49
50
51
52
#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);
class BookNoPtr;
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 &);
  friend BookNoPtr;
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;}
  double avg_price() const;
private:
  string bookNo;
  unsigned units_sold = 0;
  double revenue = 0.0;
};
class BookNoPtr
{
  const string Sales_data::*ptr = &Sales_data::bookNo;
 public:
  const string Sales_data::*data() {return ptr;}
};
#endif

Exercise 19.14

1
2
3
4
5
6
7
8
9
int main()
{
  // legal;
  auto pmf = &Screen::get_cursor;
  // pmf is a member function pointer points to Screen::get_cursor, which is a member function which accepts no parameter and return type as char;
  pmf = &Screen::get;
  // now pmf points to Screen::get, which has same function type as Screen::get_cursor(refer to my Screen class version).
}

Exercise 19.15

1
2
3
4
// pointer points to member function contains information of the class type the member belongs to;
// and the form of declaration, definition, initialization and usage of that kind of pointer are different from normal pointer;
// member function would not be implicitly transformmed to the pointer points to it.

Exercise 19.16

1
2
3
4
5
int main()
{
  using ap = double (Sales_data::*)() const;
}

Exercise 19.17

1
2
3
4
5
6
7
8
int main()
{
  using p1 = string (Sales_data::*)() const;
  using p2 = Sales_data &(Sales_data::*)(const Sales_data &);
  using p3 = Sales_data &(Sales_data::*)(const string &);
  using p4 = double (Sales_data::*)() const;
}

Exercise 19.18

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
size_t count_empty(const vector<string> &vs)
{
  function<bool (const string&)> fcn = &string::empty;
  return count_if(vs.cbegin(), vs.cend(), fcn);
}
int main()
{
  vector<string> temp = {"hello", "world", ""};
  cout << count_empty(temp) << endl;
}

Exercise 19.19

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
const Sales_data &find_ge_price(const vector<Sales_data> &vs, double price)
{
  auto f = mem_fn(&Sales_data::avg_price);
  return *(find_if(vs.cbegin(), vs.cend(),
		 [&f, price] (const Sales_data &s) {return f(s) > price;}));
}
int main()
{
  vector<Sales_data> vs = {
    Sales_data("123", 12, 21),
    Sales_data("456", 13, 22)};
  cout << find_ge_price(vs, 21) << endl;
}

Exercise 19.20

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// See TextQuery.h.
void runQueries(ifstream &infile)
{
  TextQuery tq(infile);
  while(true)
    {
      cout << "Enter word to look for, or q to quit: ";
      string s;
      if(!(cin >> s) || s == "q") break;
      print(cout, tq.query(s)) << endl;
    }
}
int main(int argc, char *argv[])
{
  ifstream ifs(argv[1]);
  runQueries(ifs);
}

TextQuery.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
#ifndef TEXTQUERY_H
#define TEXTQUERY_H
class TextQuery
{
 public:
  using line_no = vector<string>::size_type;
  TextQuery(ifstream &infile);
  TextQuery(const TextQuery &);
  TextQuery &operator=(const TextQuery &);
  class QueryResult;
  QueryResult query(const string &s) const;
 private:
  shared_ptr<vector<string>> sp1;
  map<string, shared_ptr<set<line_no>>> mp;
};
class TextQuery::QueryResult
{
  friend ostream &print(ostream &, const QueryResult &);
  string search_word;
  shared_ptr<vector<string>> sp1;
  shared_ptr<set<line_no>> sp2;
 public:
 QueryResult(const string &s,
	   shared_ptr<set<line_no>> p,
	   shared_ptr<vector<string>> file): search_word(s), sp1(file), sp2(p) {}
  QueryResult(const QueryResult &);
  QueryResult &operator=(const QueryResult &);
  set<line_no>::iterator begin() {return sp2->begin();}
  set<line_no>::iterator end() {return sp2->end();}
  shared_ptr<vector<string>> get_file() {return sp1;}
};
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;
}
  TextQuery::QueryResult::QueryResult(const QueryResult &q): sp1(make_shared<vector<string>>(*q.sp1)), sp2(make_shared<set<line_no>>(*q.sp2)), search_word(q.search_word) {}
TextQuery::QueryResult &TextQuery::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 TextQuery::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;
  }
TextQuery::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

Exercise 19.21

1
2
// See Token.h.

Token.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
150
151
152
153
#ifndef TOKEN_H
#define TOKEN_H
class Token
{
 public:
 Token(): tok(INT), ival{0} {}
 Token(const Token &t): tok(t.tok) {copyUnion(t);}
 Token(Token &&t): tok(std::move(t.tok)) {moveUnion(std::move(t));}
  Token &operator=(const Token&);
  Token &operator=(Token &&);
  ~Token()
    {
      if(tok == STR) sval.~string();
      if(tok == SAL) sal.~Sales_data();
    }
  Token &operator=(const std::string&);
  Token &operator=(std::string&&);
  Token &operator=(char);
  Token &operator=(int);
  Token &operator=(double);
  Token &operator=(const Sales_data&);
  Token &operator=(Sales_data&&);
 private:
  enum {INT, CHAR, DBL, STR, SAL} tok;
  union
  {
    char cval;
    int ival;
    double dval;
    std::string sval;
    Sales_data sal;
  };
  void copyUnion(const Token&);
  void moveUnion(Token &&);
};
void Token::copyUnion(const Token &t)
{
  switch(t.tok)
    {
    case Token::INT: ival = t.ival; break;
    case Token::CHAR: cval = t.cval; break;
    case Token::DBL: dval = t.dval; break;
    case Token::STR: new(&sval) std::string(t.sval); break;
    case Token::SAL: new(&sal) Sales_data(t.sal); break;
    }
}
void Token::moveUnion(Token &&t)
{
  switch(t.tok)
    {
    case Token::INT: ival = t.ival; break;
    case Token::CHAR: cval = t.cval; break;
    case Token::DBL: dval = t.dval; break;
    case Token::STR: new(&sval) std::string(std::move(t.sval)); break;
    case Token::SAL: new(&sal) Sales_data(std::move(t.sal)); break;
    }
}
Token &Token::operator=(const Token &t)
{
  if(tok == STR && t.tok != STR) sval.~string();
  if(tok == SAL && t.tok != SAL) sal.~Sales_data();
  if(tok == STR && t.tok == STR)
    sval = t.sval;
  else if(tok == SAL && t.tok == SAL)
    sal = t.sal;
  else
    copyUnion(t);
  tok = t.tok;
  return *this;
}
  Token &Token::operator=(Token &&t)
  {
    if(this == &t) return *this;
    if(tok == STR && t.tok != STR) sval.~string();
    if(tok == SAL && t.tok != SAL) sal.~Sales_data();
    if(tok == STR && t.tok == STR)
      sval = std::move(t.sval);
    else if(tok == SAL && t.tok == SAL)
      sal = std::move(t.sal);
    else
      moveUnion(std::move(t));
    tok = std::move(t.tok);
    return *this;
  }
    Token &Token::operator=(int i)
    {
      if(tok == STR) sval.~string();
      if(tok == SAL) sal.~Sales_data();
      ival = i;
      tok = INT;
      return *this;
    }
      Token &Token::operator=(double d)
      {
      if(tok == STR) sval.~string();
      if(tok == SAL) sal.~Sales_data();
      dval = d;
      tok = DBL;
      return *this;
      }
      Token &Token::operator=(char c)
      {
	if(tok == STR) sval.~string();
	if(tok == SAL) sal.~Sales_data();
	cval = c;
	tok = CHAR;
	return *this;
      }
	Token &Token::operator=(const std::string &s)
	{
	  if(tok == SAL) sal.~Sales_data();
	  if(tok == STR)
	    sval = s;
	  else
	    new(&sval) std::string(s);
	  tok = STR;
	  return *this;
	}

	  Token &Token::operator=(const Sales_data &s)
	  {
	    if(tok == STR) sval.~string();
	    if(tok == SAL)
	      sal = s;
	    else
	      new(&sal) Sales_data(s);
	    tok = SAL;
	    return *this;
	  }

	    Token &Token::operator=(string &&s)
	    {
	      if(tok == SAL) sal.~Sales_data();
	      if(tok == STR)
		sval = std::move(s);
	      else
		new(&sval) std::string(std::move(s));
	      tok = STR;
	      return *this;
	    }

	      Token &Token::operator=(Sales_data &&s)
	      {
		if(tok == STR) sval.~string();
		if(tok == SAL)
		  sal = std::move(s);
		else
		  new(&sal) Sales_data(std::move(s));
		tok = SAL;
		return *this;
	      }
#endif

Exercise 19.22

1
2
// See Token.h.

Token.h

Exercise 19.23

1
2
// See Token.h.

Token.h

Exercise 19.24

1
2
3
4
5
6
// For self assignment of Token type object, since the data member tok is exactly the same;
// for copy assignment, follow the way which is illustrated in text book;
// there is no call of constructor or destructor of string class type and Sales_data class type, for any member of union the correspond assignment operation would do the job;
// for mvoe assignment, as in my implementation;
// check if it is a self-assignment, if so, do nothing 'return *this'.

Exercise 19.25

1
2
// see Token.h.

Token.h

Exercise 19.26

1
2
3
4
extern "C" int compute(int *, int); // declares a C function which accpets two parateters of int * and int type, then its return value is int type;
extern "C" double compute(double *, double); // declares a C function which accpets two parateters of double * and double type, then its return value is double type;
// illegal, due to C programming language does not support overload functions.