From bfc4461b684c766d72b0299f02e819d6ae6759f6 Mon Sep 17 00:00:00 2001 From: pezy Date: Tue, 16 May 2017 14:26:15 +0800 Subject: [PATCH] improving markdown format. --- README.md | 9 +- ch01/README.md | 86 +++++++----- ch02/README.md | 331 ++++++++++++++++++++--------------------------- ch03/README.md | 179 ++++++++++++++++--------- ch05/README.md | 95 +++++++++----- ch06/README.md | 56 ++++++-- ch07/README.md | 244 ++++++++++++++-------------------- ch08/README.md | 20 ++- ch10/README.md | 133 +++++++------------ ch11/README.md | 63 ++++++--- ch12/README.md | 55 ++++++-- ch13/README.md | 216 +++++++++++-------------------- ch13/ex13_58.cpp | 2 + ch14/README.md | 198 ++++++++++++++++++---------- ch15/README.md | 123 ++++++++++++------ ch16/README.md | 63 +++------ ch18/README.md | 31 +++-- 17 files changed, 1001 insertions(+), 903 deletions(-) diff --git a/README.md b/README.md index 37b6b441..ae08d9d3 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,20 @@ -##C++ Primer 5th Answers +# C++ Primer 5th Answers + +--- [![GitHub issues](https://img.shields.io/github/issues/pezy/CppPrimer.svg)](https://github.com/pezy/CppPrimer/issues) [![GitHub license](https://img.shields.io/badge/license-CC0-blue.svg)](https://raw.githubusercontent.com/pezy/Cpp-Primer/master/LICENSE) [![](https://img.shields.io/badge/%E4%B8%AD%E6%96%87-%E8%AE%A8%E8%AE%BA%E5%8C%BA-yellowgreen.svg)](https://github.com/ReadingLab/Discussion-for-Cpp) [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/pezy/0.99) +[![Donate](https://img.shields.io/badge/Donate-%E6%94%AF%E4%BB%98%E5%AE%9D-blue.svg)](http://devnotes.org/img/alipay.jpg) -### Notes +## Notes - Use `GCC 4.9+`, `Clang 3.4+`, `MSVC 14+`, and [others](http://en.cppreference.com/w/cpp/compiler_support). - Use `-std=c++11`(recommend: `-pedantic -Wall`) flag for compiling. - Have you discovered incorrect information? [Submit](https://github.com/pezy/CppPrimer/issues/new). -### Contents +## Contents - [Chapter 1. Getting Started](ch01/README.md) - Part I: The Basics diff --git a/ch01/README.md b/ch01/README.md index 0ac501a5..9cafb745 100644 --- a/ch01/README.md +++ b/ch01/README.md @@ -1,34 +1,33 @@ # Chapter 1. Getting Started -##Exercise 1.1 +## Exercise 1.1 > Review the documentation for your compiler and determine what file naming convention it uses. Compile and run the main program from page 2. -### Windows +- Windows ![windows](https://cloud.githubusercontent.com/assets/1147451/8334465/a87e3528-1aca-11e5-877d-c610f087fc40.png) - -### Linux +- Linux ![Linux](https://cloud.githubusercontent.com/assets/1147451/8334480/c160e75c-1aca-11e5-92d5-7d0a05fbf493.png) - -##Exercise 1.2 +## Exercise 1.2 > Exercise 1.2: Change the program to return -1. A return value of -1 is often treated as an indicator that the program failed. Recompile and rerun your program to see how your system treats a failure indicator from main. -###Windows +- Windows ![image](https://cloud.githubusercontent.com/assets/1147451/8335952/72179d5e-1ad3-11e5-84ff-e924816e64a3.png) -###Linux +- Linux ![image](https://cloud.githubusercontent.com/assets/1147451/8335963/8debbc5e-1ad3-11e5-9761-013139d291d8.png) **255**? why? check [this](http://www.tldp.org/LDP/abs/html/exitcodes.html) -##Exercise 1.3 +## Exercise 1.3 + > Write a program to print Hello, World on the standard output. ```cpp @@ -41,7 +40,8 @@ int main() } ``` -##Exercise 1.4 +## Exercise 1.4 + > Our program used the addition operator, +, to add two numbers. Write a program that uses the multiplication operator, *, to print the product instead. ```cpp @@ -58,7 +58,7 @@ int main() } ``` -##Exercise 1.5 +## Exercise 1.5 > We wrote the output in one large statement. Rewrite the program to use a separate statement to print each operand. @@ -81,12 +81,13 @@ int main() } ``` -##Exercise 1.6 +## Exercise 1.6 + > Explain whether the following program fragment is legal. It's illegal. -**[Error] expected primary-expression before '<<' token** +**`[Error] expected primary-expression before '<<' token`** Fixed it: remove the spare semicolons. @@ -96,11 +97,12 @@ std::cout << "The sum of " << v1 << " is " << v1 + v2 << std::endl; ``` -##Exercise 1.7 +## Exercise 1.7 > Compile a program that has incorrectly nested comments. Example: + ```cpp /* * comment pairs /* */ cannot nest. @@ -117,16 +119,17 @@ Compiled result(g++): ![ex1_7](https://cloud.githubusercontent.com/assets/1147451/8334581/4fb4a408-1acb-11e5-98e3-54c0929198ec.png) - -##Exercise 1.8 +## Exercise 1.8 > Indicate which, if any, of the following output statements are legal: + ```cpp std::cout << "/*"; std::cout << "*/"; std::cout << /* "*/" */; std::cout << /* "*/" /* "/*" */; ``` + > After you’ve predicted what will happen, test your answers by compiling a program with each of these statements. Correct any errors you encounter. Compiled result(g++): @@ -134,6 +137,7 @@ Compiled result(g++): ![ex1_8](https://cloud.githubusercontent.com/assets/1147451/8334603/6aa321e0-1acb-11e5-988a-57e87a53b141.png) Corrected? just added a quote: + ```cpp std::cout << "/*"; std::cout << "*/"; @@ -142,16 +146,21 @@ std::cout << /* "*/" /* "/*" */; ``` Output: + ```sh /**/ */ /* ``` -##[Exercise 1.9](ex1_09.cpp) -##[Exercise 1.10](ex1_10.cpp) -##[Exercise 1.11](ex1_11.cpp) +## [Exercise 1.9](ex1_09.cpp) + +## [Exercise 1.10](ex1_10.cpp) + +## [Exercise 1.11](ex1_11.cpp) + +## Exercise 1.12 -##Exercise 1.12 > What does the following for loop do? What is the final value of sum? + ```cpp int sum = 0; for (int i = -100; i <= 100; ++i) @@ -160,10 +169,12 @@ for (int i = -100; i <= 100; ++i) the loop sums the numbers from -100 to 100. the final value of sum is zero. -##Exercise 1.13 +## Exercise 1.13 + > Rewrite the exercises from 1.4.1 (p. 13) using for loops. **Ex1.9**: + ```cpp #include @@ -180,6 +191,7 @@ int main() ``` **Ex1.10**: + ```cpp #include @@ -194,6 +206,7 @@ int main() ``` **Ex1.11**: + ```cpp #include @@ -217,7 +230,8 @@ int main() } ``` -##Exercise 1.14 +## Exercise 1.14 + > Compare and contrast the loops that used a `for` with those using a `while`. Are there advantages or disadvantages to using either form? - Advantage of `for` and disadvantage of `while`: @@ -231,12 +245,13 @@ int main() [A similar question on Stack Overflow](http://stackoverflow.com/questions/2950931/for-vs-while-in-c-programming) -##Exercise 1.15 +## Exercise 1.15 + > Write programs that contain the common errors discussed in the box on page 16. Familiarize yourself with the messages the compiler generates. Self-training. -##Exercise 1.16 +## Exercise 1.16 > Write your own version of a program that prints the sum of a set of integers read from `cin`. @@ -253,28 +268,27 @@ int main() } ``` -##Exercise 1.17 +## Exercise 1.17 > What happens in the program presented in this section if the input values are all equal? What if there are no duplicated values? If all equal, the count will be printed out. If there are no duplicated values, A new line will be printed when `Enter` clicked. -##Exercise 1.18 +## Exercise 1.18 > Compile and run the program from this section giving it only equal values as input. Run it again giving it values in which no number is repeated. ![ex1_18](https://cloud.githubusercontent.com/assets/1147451/8335404/0861c478-1ad0-11e5-8083-c05a0cd9e758.png) - -##Exercise 1.19 +## Exercise 1.19 > Revise the program you wrote for the exercises in § 1.4.1 (p. 13) that printed a range of numbers so that it handles input in which the first number is smaller than the second. check [ex1_11.cpp](https://github.com/pezy/Cpp-Primer/blob/master/ch01/ex1_11.cpp) -##Exercise 1.20 +## Exercise 1.20 -> http://www.informit.com/title/032174113 contains a copy of Sales_item.h in the Chapter 1 code directory. Copy that file to your working directory. Use it to write a program that reads a set of book sales transactions, writing each transaction to the standard output. +> contains a copy of Sales_item.h in the Chapter 1 code directory. Copy that file to your working directory. Use it to write a program that reads a set of book sales transactions, writing each transaction to the standard output. check [code](ex1_20.cpp). @@ -282,15 +296,15 @@ Test it using the `data`/`book.txt`: ![ex1_20](https://cloud.githubusercontent.com/assets/1147451/8335638/8f5c2bca-1ad1-11e5-9c51-288382710df2.png) +## Exercise 1.21 -##Exercise 1.21 > Write a program that reads two `Sales_item` objects that have the same ISBN and produces their sum. The program should check whether the objects have the same ISBN.(check 1.5.2) [Code](ex1_21.cpp) -##Exercise 1.22 +## Exercise 1.22 > Write a program that reads several transactions for the same ISBN. Write the sum of all the transactions that were read. @@ -300,7 +314,8 @@ Tip: this program will appear in the section 1.6. ![ex1_22](https://cloud.githubusercontent.com/assets/1147451/8335700/d85ee22c-1ad1-11e5-9612-1155145606c1.png) -##Exercise 1.23 +## Exercise 1.23 + > Write a program that reads several transactions and counts how many transactions occur for each ISBN. @@ -308,15 +323,16 @@ Tip: please review the `1.4.4`. [Code](ex1_23.cpp). -##Exercise 1.24 +## Exercise 1.24 + > Test the previous program by giving multiple transactions representing multiple ISBNs. The records for each ISBN should be grouped together. `data`/`book.txt` may be used as the records. ![ex1_24](https://cloud.githubusercontent.com/assets/1147451/8335734/0fbefbbc-1ad2-11e5-9df3-fa1203dffb42.png) +## Exercise 1.25 -##Exercise 1.25 > Using the `Sales_item.h` header from the Web site, compile and execute the bookstore program presented in this section. ![ex1_25](https://cloud.githubusercontent.com/assets/1147451/8335742/1efb475c-1ad2-11e5-9484-69ae44b79385.png) diff --git a/ch02/README.md b/ch02/README.md index d7c58ffe..ee8f5649 100644 --- a/ch02/README.md +++ b/ch02/README.md @@ -1,8 +1,6 @@ -Chapter 2. Variables and Basic Types -==================================== +# Chapter 2. Variables and Basic Types -Exercise 2.1 ------------- +## Exercise 2.1 > What are the differences between `int`, `long`, `long long`, and `short`? Between an `unsigned` and a `signed` type? Between a `float` and a `double`? @@ -14,36 +12,34 @@ The C and C++ standards do not specify the representation of float, double and l **Usage**: -- Use `int` for integer arithmetic. `short` is usually too small and, in practice,`long` often has the same size as `int`. If your data values are larger than the minimum guaranteed size of an `int`, then use `long long`. (In a word: short < **int** < long < long long) +- Use `int` for integer arithmetic. `short` is usually too small and, in practice,`long` often has the same size as `int`. If your data values are larger than the minimum guaranteed size of an `int`, then use `long long`. (In a word: short < **int** < long < long long) -- Use an unsigned type when you know that the values cannot be negative. (In a word: no negative, unsigned.) +- Use an unsigned type when you know that the values cannot be negative. (In a word: no negative, unsigned.) -- Use double for floating-point computations; float usually does not have enough precision, and the cost of double-precision calculations versus single-precision is negligible. In fact, on some machines, double-precision operations are faster than single. The precision offered by long double usually is unnecessary and often entails considerable run-time cost. (In a word: float < **double** < long double) +- Use double for floating-point computations; float usually does not have enough precision, and the cost of double-precision calculations versus single-precision is negligible. In fact, on some machines, double-precision operations are faster than single. The precision offered by long double usually is unnecessary and often entails considerable run-time cost. (In a word: float < **double** < long double) Reference: -- [What are the criteria for choosing between short / int / long data types?](http://www.parashift.com/c++-faq/choosing-int-size.html) -- [Difference between float and double](http://stackoverflow.com/questions/2386772/difference-between-float-and-double) -- Advice: Deciding which Type to Use(This book.) +- [What are the criteria for choosing between short / int / long data types?](http://www.parashift.com/c++-faq/choosing-int-size.html) +- [Difference between float and double](http://stackoverflow.com/questions/2386772/difference-between-float-and-double) +- Advice: Deciding which Type to Use(This book.) -Exercise 2.2 ------------- +## Exercise 2.2 > To calculate a mortgage payment, what types would you use for the rate, principal, and payment? Explain why you selected each type. use `double`, or also `float`. -- The rate most like that: `4.50 % per year`. -- The principal most like that: `$854.36` -- The payment most like that: `$1,142.36` +- The rate most like that: `4.50 % per year`. +- The principal most like that: `$854.36` +- The payment most like that: `$1,142.36` Reference: -- [mortgage-calculator](http://www.bankrate.com/calculators/mortgages/mortgage-calculator.aspx) -- [What's in a Mortgage Payment?](http://www.homeloanlearningcenter.com/mortgagebasics/whatsinamortgagepayment.htm) +- [mortgage-calculator](http://www.bankrate.com/calculators/mortgages/mortgage-calculator.aspx) +- [What's in a Mortgage Payment?](http://www.homeloanlearningcenter.com/mortgagebasics/whatsinamortgagepayment.htm) -Exercise 2.3 ------------- +## Exercise 2.3 > What output will the following code produce? > @@ -60,26 +56,24 @@ Exercise 2.3 Output(g++ 4.8): -``` +```shell 32 4294967264 32 -32 0 0 ``` -Exercise 2.4 ------------- +## Exercise 2.4 > Write a program to check whether your predictions were correct. If not, study this section until you understand what the problem is. [Here](ex2_04.cpp) is the code, please test it in your computer. -Exercise 2.5 ------------- +## Exercise 2.5 > Determine the type of each of the following literals. Explain the differences among the literals in each of the four examples: > -> - (a) 'a', L'a', "a", L"a" -> - (b) 10, 10u, 10L, 10uL, 012, 0xC -> - (c) 3.14, 3.14f, 3.14L -> - (d) 10, 10u, 10., 10e-2 +> - (a) 'a', L'a', "a", L"a" +> - (b) 10, 10u, 10L, 10uL, 012, 0xC* +> - (c) 3.14, 3.14f, 3.14L* +> - (d) 10, 10u, 10., 10e-2 (a): character literal, wide character literal, string literal, string wide character literal. @@ -89,8 +83,7 @@ Exercise 2.5 (d): decimal, unsigned decimal, double, double. -Exercise 2.6 ------------- +## Exercise 2.6 > What, if any, are the differences between the following definitions: > @@ -103,18 +96,17 @@ The first line's integer is decimal. The second line: -1. `int month = 09` is invalid, cause octal don't have digit `9`. -2. `day` is octal. +1. `int month = 09` is invalid, cause octal don't have digit `9`. +1. `day` is octal. -Exercise 2.7 ------------- +## Exercise 2.7 > What values do these literals represent? What type does each have? > -> - (a) "Who goes with F\145rgus?\012" -> - (b) 3.14e1L -> - (c) 1024f -> - (d) 3.14L +> - (a) "Who goes with F\145rgus?\012" +> - (b) 3.14e1L +> - (c) 1024f +> - (d) 3.14L (a): Who goes with Fergus?(new line) "string" @@ -126,10 +118,9 @@ Exercise 2.7 Reference: -- [ASCII Table](http://www.asciitable.com/) +- [ASCII Table](http://www.asciitable.com/) -Exercise 2.8 ------------- +## Exercise 2.8 > Using escape sequences, write a program to print 2M followed by a newline. Modify the program to print 2, then a tab, then an M, followed by a newline. @@ -144,15 +135,13 @@ int main() ``` -Exercise 2.9 ------------- +## Exercise 2.9 > Explain the following definitions. For those that are illegal, explain what’s wrong and how to correct it. -> -> - (a) `std::cin >> int input_value;` -> - (b) `int i = { 3.14 };` -> - (c) `double salary = wage = 9999.99;` -> - (d) `int i = 3.14;` +> - (a) `std::cin >> int input_value;` +> - (b) `int i = { 3.14 };` +> - (c) `double salary = wage = 9999.99;` +> - (d) `int i = 3.14;` (a): error: expected '(' for function-style cast or type construction. @@ -180,8 +169,7 @@ double salary = wage = 9999.99; double i = 3.14; ``` -Exercise 2.10 -------------- +## Exercise 2.10 > What are the initial values, if any, of each of the following variables? > @@ -195,43 +183,38 @@ Exercise 2.10 > } > ``` -- `global_str` is global variable, so the value is empty string. -- `global_int` is global variable, so the value is zero. -- `local_int` is a local variable which is not uninitialized, so it has a undefined value. -- `local_str` is also a local variable which is not uninitialized, but it has a value that is defined by the class. So it is empty string. +- `global_str` is global variable, so the value is empty string. +- `global_int` is global variable, so the value is zero. +- `local_int` is a local variable which is not uninitialized, so it has a undefined value. +- `local_str` is also a local variable which is not uninitialized, but it has a value that is defined by the class. So it is empty string. PS: please read P44 in the English version, P40 in Chinese version to get more information. > Uninitialized objects of built-in type defined inside a function body have a undefined value. Objects of class type that we do not explicitly initialize have a value that is defined by class. -Exercise 2.11 -------------- +## Exercise 2.11 > Explain whether each of the following is a declaration or a definition: -> -> - (a) `extern int ix = 1024;` -> - (b) `int iy;` -> - (c) `extern int iz;` +> - (a) `extern int ix = 1024;` +> - (b) `int iy;` +> - (c) `extern int iz;` -- (a): definition. -- (b): definition. -- (c): declaration. +- (a): definition. +- (b): definition. +- (c): declaration. -Exercise 2.12 -------------- +## Exercise 2.12 > Which, if any, of the following names are invalid? -> -> - (a) `int double = 3.14;` -> - (b) `int _;` -> - (c) `int catch-22;` -> - (d) `int 1_or_2 = 1;` -> - (e) `double Double = 3.14;` +> - (a) `int double = 3.14;` +> - (b) `int _;` +> - (c) `int catch-22;` +> - (d) `int 1_or_2 = 1;` +> - (e) `double Double = 3.14;` `a`, `c`, `d` are invalid. -Exercise 2.13 -------------- +## Exercise 2.13 > What is the value of j in the following program? > @@ -246,8 +229,7 @@ Exercise 2.13 `100`. cause the global `i` was hidden by the local `i`. -Exercise 2.14 -------------- +## Exercise 2.14 > Is the following program legal? If so, what values are printed? @@ -260,23 +242,20 @@ std::cout << i << " " << sum << std::endl; Yes. It is legal.Printed:`100, 45.` -Exercise 2.15 -------------- +## Exercise 2.15 > Which of the following definitions, if any, are invalid? Why? -> -> - (a) `int ival = 1.01;` -> - (b) `int &rval1 = 1.01;` -> - (c) `int &rval2 = ival;` -> - (d) `int &rval3;` +> - (a) `int ival = 1.01;` +> - (b) `int &rval1 = 1.01;` +> - (c) `int &rval2 = ival;` +> - (d) `int &rval3;` -- (a): valid. -- (b): invalid. initializer must be an object. -- (c): valid. -- (d): invalid. a reference must be initialized. +- (a): valid. +- (b): invalid. initializer must be an object. +- (c): valid. +- (d): invalid. a reference must be initialized. -Exercise 2.16 -------------- +## Exercise 2.16 > Which, if any, of the following assignments are invalid? If they are valid, explain what they do. > @@ -285,18 +264,17 @@ Exercise 2.16 > double d = 0, &r2 = d; > ``` > -> - (a) r2 = 3.14159; -> - (b) r2 = r1; -> - (c) i = r2; -> - (d) r1 = d; +> - (a) r2 = 3.14159; +> - (b) r2 = r1; +> - (c) i = r2; +> - (d) r1 = d; -- (a): valid. let d equal 3.14159. -- (b): valid. automatic convert will happen. -- (c): valid. but value will be truncated. -- (d): valid. but value will be truncated. +- (a): valid. let d equal 3.14159. +- (b): valid. automatic convert will happen. +- (c): valid. but value will be truncated. +- (d): valid. but value will be truncated. -Exercise 2.17 -------------- +## Exercise 2.17 > What does the following code print? > @@ -308,8 +286,7 @@ Exercise 2.17 `10, 10` -Exercise 2.18 -------------- +## Exercise 2.18 > Write code to change the value of a pointer. Write code to change the value to which the pointer points. @@ -323,8 +300,7 @@ p1 = &b; *p2 = b; ``` -Exercise 2.19 -------------- +## Exercise 2.19 > Explain the key differences between pointers and references. @@ -336,17 +312,16 @@ the reference is "another name" of an **object**. **key difference**: -1. a reference is another name of an **already existing** object. a pointer is an object in its **own right**. -2. Once initialized, a reference remains **bound to** its initial object. There is **no way** to rebind a reference to refer to a different object. a pointer can be **assigned** and **copied**. -3. a reference always get the object to which the reference was initially bound. a single pointer can point to **several different objects** over its lifetime. -4. a reference must be initialized. a pointer need **not be** initialized at the time it is defined. +1. a reference is another name of an **already existing** object. a pointer is an object in its **own right**. +1. Once initialized, a reference remains **bound to** its initial object. There is **no way** to rebind a reference to refer to a different object. a pointer can be **assigned** and **copied**. +1. a reference always get the object to which the reference was initially bound. a single pointer can point to **several different objects** over its lifetime. +1. a reference must be initialized. a pointer need **not be** initialized at the time it is defined. **Usage advise**: check [here](http://www.parashift.com/c%2B%2B-faq-lite/refs-vs-ptrs.html) -Exercise 2.20 -------------- +## Exercise 2.20 > What does the following program do? > @@ -357,8 +332,7 @@ Exercise 2.20 `p1` pointer to `i`, `i`'s value changed to 1764(42*42) -Exercise 2.21 -------------- +## Exercise 2.21 > Explain each of the following definitions. Indicate whether any are illegal and, if so, why. > @@ -366,16 +340,15 @@ Exercise 2.21 > int i = 0; > ``` > -> - (a) `double* dp = &i;` -> - (b) `int *ip = i;` -> - (c) `int *p = &i;` +> - (a) `double* dp = &i;` +> - (b) `int *ip = i;` +> - (c) `int *p = &i;` -- (a): illegal, cannot initialize a variable of type `double *` with an rvalue of type `int *` -- (b): illegal, cannot initialize a variable of type `int *` with an lvalue of type `int` -- (c): legal. +- (a): illegal, cannot initialize a variable of type `double *` with an rvalue of type `int *` +- (b): illegal, cannot initialize a variable of type `int *` with an lvalue of type `int` +- (c): legal. -Exercise 2.22 -------------- +## Exercise 2.22 > Assuming p is a pointer to int, explain the following code: > @@ -384,15 +357,13 @@ Exercise 2.22 > if (*p) // whether the value pointed by p is zero? > ``` -Exercise 2.23 -------------- +## Exercise 2.23 > Given a pointer p, can you determine whether p points to a valid object? If so, how? If not, why not? No. Because more information needed to determine whether the pointer is valid or not. -Exercise 2.24 -------------- +## Exercise 2.24 > Why is the initialization of `p` legal but that of `lp` illegal? > @@ -404,21 +375,19 @@ Exercise 2.24 Because the type `void*` is a special pointer type that can hold the address of any object. But we cannot initialize a variable of type `long *` with an rvalue of type `int *` -Exercise 2.25 -------------- +## Exercise 2.25 > Determine the types and values of each of the following variables. > -> - (a) `int* ip, i, &r = i;` -> - (b) `int i, *ip = 0;` -> - (c) `int* ip, ip2;` +> - (a) `int* ip, i, &r = i;` +> - (b) `int i, *ip = 0;` +> - (c) `int* ip, ip2;` -- (a): `ip` is a pointer to `int`, `i` is an `int`, `r` is a reference to `int` `i`. -- (b): `ip` is a valid, null pointer, and `i` is an `int`. -- (c): `ip` is a pointer to `int`, and `ip2` is an `int`. +- (a): `ip` is a pointer to `int`, `i` is an `int`, `r` is a reference to `int` `i`. +- (b): `ip` is a valid, null pointer, and `i` is an `int`. +- (c): `ip` is a pointer to `int`, and `ip2` is an `int`. -Exercise 2.26 -------------- +## Exercise 2.26 > Which of the following are legal? For those that are illegal, explain why. > @@ -429,8 +398,7 @@ Exercise 2.26 > ++cnt; ++sz; // illegal, attempt to write to const object(sz). > ``` -Exercise 2.27 -------------- +## Exercise 2.27 > Which of the following initializations are legal? Explain why. > @@ -444,8 +412,7 @@ Exercise 2.27 > const int i2 = i, &r = i; // legal. > ``` -Exercise 2.28 -------------- +## Exercise 2.28 > Explain the following definitions. Identify any that are illegal. > @@ -457,10 +424,9 @@ Exercise 2.28 > const int *p; // legal. a pointer to const int. > ``` -Exercise 2.29 -------------- +## Exercise 2.29 -> Using the variables in the previous exercise, which of the following assignments are legal? Explain why. +> Using the variables in the previous ## Exercise, which of the following assignments are legal? Explain why. > > ```cpp > i = ic; // legal. @@ -471,8 +437,7 @@ Exercise 2.29 > ic = *p3; // illegal. ic is a const int. > ``` -Exercise 2.30 -------------- +## Exercise 2.30 > For each of the following declarations indicate whether the object being declared has top-level or low-level `const`. > @@ -482,14 +447,13 @@ Exercise 2.30 > const int *p2 = &v2, *const p3 = &i, &r2 = v2; > ``` -- v2 is top-level `const`, p2 is low-level `const`. -- p3: right-most `const` is top-level, left-most is low-level. -- r2 is low-level `const`. +- v2 is top-level `const`, p2 is low-level `const`. +- p3: right-most `const` is top-level, left-most is low-level. +- r2 is low-level `const`. -Exercise 2.31 -------------- +## Exercise 2.31 -> Given the declarations in the previous exercise determine whether the following assignments are legal. Explain how the top-level or low-level `const` applies in each case. +> Given the declarations in the previous ## Exercise determine whether the following assignments are legal. Explain how the top-level or low-level `const` applies in each case. > > ```cpp > r1 = v2; // legal, top-level const in v2 is ignored. @@ -499,12 +463,11 @@ Exercise 2.31 > p2 = p3; // legal, p2 has the same low-level const qualification as p3. > ``` -Exercise 2.32 -------------- +## Exercise 2.32 > Is the following code legal or not? If not, how might you make it legal? -``` +```cpp int null = 0, *p = null; ``` @@ -514,8 +477,7 @@ illegal. int null = 0, *p = nullptr; ``` -Exercise 2.33 -------------- +## Exercise 2.33 > Using the variable definitions from this section, determine what happens in each of these assignments: > @@ -528,15 +490,13 @@ Exercise 2.33 > g = 42; // ERROR, g is a const int& that is bound to ci. > ``` -Exercise 2.34 -------------- +## Exercise 2.34 -> Write a program containing the variables and assignments from the previous exercise. Print the variables before and after the assignments to check whether your predictions in the previous exercise were correct. If not, study the examples until you can convince yourself you know what led you to the wrong conclusion. +> Write a program containing the variables and assignments from the previous ## Exercise. Print the variables before and after the assignments to check whether your predictions in the previous ## Exercise were correct. If not, study the examples until you can convince yourself you know what led you to the wrong conclusion. check the [code](ex2_34.cpp). -Exercise 2.35 -------------- +## Exercise 2.35 > Determine the types deduced in each of the following definitions. Once you’ve figured out the types, write a program to see whether you were correct. > @@ -548,17 +508,16 @@ Exercise 2.35 > const auto j2 = i, &k2 = i; > ``` -- `i` is `const int`. -- `j` is `int`. -- `k` is `const int&`. -- `p` is `const int *`. -- `j2` is `const int`. -- `k2` is `const int&`. +- `i` is `const int`. +- `j` is `int`. +- `k` is `const int&`. +- `p` is `const int *`. +- `j2` is `const int`. +- `k2` is `const int&`. check [Here](ex2_35.cpp). -Exercise 2.36 -------------- +## Exercise 2.36 > In the following code, determine the type of each variable and the value each variable has when the code finishes: > @@ -572,8 +531,7 @@ Exercise 2.36 `c` is an int, `d` is a reference of `a`. all their value are `4`. -Exercise 2.37 -------------- +## Exercise 2.37 > Assignment is an example of an expression that yields a reference type. The type is a reference to the type of the left-hand operand. That is, if i is an int, then the type of the expression `i = x` is `int&`. Using that knowledge, determine the type and value of each variable in this code: > @@ -583,11 +541,10 @@ Exercise 2.37 > decltype(a = b) d = a; > ``` -- `c` is an int, `d` is a reference of int. -- the value: `a = 3, b = 4, c = 3, d = 3` +- `c` is an int, `d` is a reference of int. +- the value: `a = 3, b = 4, c = 3, d = 3` -Exercise 2.38 -------------- +## Exercise 2.38 > Describe the differences in type deduction between `decltype` and auto. Give an example of an expression where auto and `decltype` will deduce the same type and an example where they will deduce differing types. @@ -607,8 +564,7 @@ decltype(r) d = i; More? check [here](http://stackoverflow.com/questions/21369113/what-is-the-difference-between-auto-and-decltypeauto-when-returning-from-a-fun) and [here](http://stackoverflow.com/questions/12084040/decltype-vs-auto) -Exercise 2.39 -------------- +## Exercise 2.39 > Compile the following program to see what happens when you forget the semicolon after a class definition. Remember the message for future reference. > @@ -622,12 +578,11 @@ Exercise 2.39 Error message: `[Error] expected ';' after struct definition` -Exercise 2.40 -------------- +## Exercise 2.40 > Write your own version of the `Sales_data` class. -``` +```cpp struct Sale_data { std::string bookNo; std::string bookName; @@ -638,12 +593,11 @@ struct Sale_data { }; ``` -Exercise 2.41 -------------- +## Exercise 2.41 -> Use your Sales_data class to rewrite the exercises in 1.5.1(p. 22), 1.5.2(p. 24), and 1.6(p. 25). For now, you should define your Sales_data class in the same file as your main function. +> Use your Sales_data class to rewrite the ## Exercises in 1.5.1(p. 22), 1.5.2(p. 24), and 1.6(p. 25). For now, you should define your Sales_data class in the same file as your main function. -**1.5.1** +### 1.5.1 ```cpp #include @@ -667,7 +621,7 @@ int main() } ``` -**1.5.2** +### 1.5.2 ```cpp #include @@ -706,7 +660,7 @@ int main() } ``` -**1.6** +### 1.6 ```cpp #include @@ -762,12 +716,11 @@ int main() } ``` -Exercise 2.42 -------------- +## Exercise 2.42 -> Write your own version of the `Sales_data.h` header and use it to rewrite the exercise from 2.6.2(p. 76) +> Write your own version of the `Sales_data.h` header and use it to rewrite the ## Exercise from 2.6.2(p. 76) -- [Sales_data.h](ex2_42.h) -- [1.5.1.](ex2_42_1.cpp) -- [1.5.2.](ex2_42_2.cpp) -- [1.6.](ex2_42_3.cpp) +- [Sales_data.h](ex2_42.h) +- [1.5.1.](ex2_42_1.cpp) +- [1.5.2.](ex2_42_2.cpp) +- [1.6.](ex2_42_3.cpp) diff --git a/ch03/README.md b/ch03/README.md index f86770dd..6ff0f31d 100644 --- a/ch03/README.md +++ b/ch03/README.md @@ -1,6 +1,11 @@ -##Exercise 3.1 : [part1](ex3_01a.cpp) | [part2](ex3_01b.cpp) -##Exercise 3.2 : [part1](ex3_02a.cpp) | [part2](ex3_02b.cpp) -##Exercise 3.3 +# Chapter 3. Strings, Vectors, and Arrays + +## Exercise 3.1 : [part1](ex3_01a.cpp) | [part2](ex3_01b.cpp) + +## Exercise 3.2 : [part1](ex3_02a.cpp) | [part2](ex3_02b.cpp) + +## Exercise 3.3 + >Explain how whitespace characters are handled in the string input operator and in the `getline` function. @@ -22,10 +27,14 @@ read to termination and discard newline [Read more](http://www.cplusplus.com/reference/string/string/getline/) -##Exercise 3.4 : [part1](ex3_04a.cpp) | [part2](ex3_04b.cpp) -##Exercise 3.5 : [part1](ex3_05a.cpp) | [part2](ex3_05b.cpp) -##[Exercise 3.6](ex3_06.cpp) -##Exercise 3.7 +## Exercise 3.4 : [part1](ex3_04a.cpp) | [part2](ex3_04b.cpp) + +## Exercise 3.5 : [part1](ex3_05a.cpp) | [part2](ex3_05b.cpp) + +## [Exercise 3.6](ex3_06.cpp) + +## Exercise 3.7 + >What would happen if you define the loop control variable in the previous exercise as type char? Predict the results and then change your program to use a char to see if you were right. @@ -37,9 +46,12 @@ No different. We use `auto` to let the compiler determine the type of `c`. which in this case will be `char&`. -##[Exercise 3.8](ex3_08.cpp) -##Exercise 3.9 +## [Exercise 3.8](ex3_08.cpp) + +## Exercise 3.9 + >What does the following program do? Is it valid? If not, why not? + ```cpp string s; cout << s[0] << endl; @@ -47,9 +59,12 @@ cout << s[0] << endl; Try to get the first element of the `string`. It is invalid, cause this is **undefined behavior**. -##[Exercise 3.10](ex3_10.cpp) -##Exercise 3.11 +## [Exercise 3.10](ex3_10.cpp) + +## Exercise 3.11 + >Is the following range for legal? If so, what is the type of c? + ```cpp const string s = "Keep out!"; for (auto &c : s){/*... */} @@ -64,19 +79,23 @@ For example: The type of `c` is `const char&`. read-only variable is not assignable. -##Exercise 3.12 +## Exercise 3.12 + >Which, if any, of the following vector definitions are in error? For those that are legal, explain what the definition does. For those that are not legal, explain why they are illegal. + ```cpp vector> ivec; // legal(c++11), vectors. vector svec = ivec; // illegal, different type. vector svec(10, "null"); // legal, vector have 10 strings: "null". ``` -##Exercise 3.13 +## Exercise 3.13 + >How many elements are there in each of the following vectors? What are the values of the elements? + ```cpp vector v1; // size:0, no values. vector v2(10); // size:10, value:0 @@ -87,19 +106,32 @@ vector v6{10}; // size:10, value:"" vector v7{10, "hi"}; // size:10, value:"hi" ``` -##[Exercise 3.14](ex3_14.cpp) -##[Exercise 3.15](ex3_15.cpp) -##[Exercise 3.16](ex3_16.cpp) -##[Exercise 3.17](ex3_17.cpp) -##[Exercise 3.18](ex3_18.cpp) -##[Exercise 3.19](ex3_19.cpp) -##[Exercise 3.20](ex3_20.cpp) -##[Exercise 3.21](ex3_21.cpp) -##[Exercise 3.22](ex3_22.cpp) -##[Exercise 3.23](ex3_23.cpp) -##[Exercise 3.24](ex3_24.cpp) -##[Exercise 3.25](ex3_25.cpp) -##Exercise 3.26 +## [Exercise 3.14](ex3_14.cpp) + +## [Exercise 3.15](ex3_15.cpp) + +## [Exercise 3.16](ex3_16.cpp) + +## [Exercise 3.17](ex3_17.cpp) + +## [Exercise 3.18](ex3_18.cpp) + +## [Exercise 3.19](ex3_19.cpp) + +## [Exercise 3.20](ex3_20.cpp) + +## [Exercise 3.21](ex3_21.cpp) + +## [Exercise 3.22](ex3_22.cpp) + +## [Exercise 3.23](ex3_23.cpp) + +## [Exercise 3.24](ex3_24.cpp) + +## [Exercise 3.25](ex3_25.cpp) + +## Exercise 3.26 + >In the binary search program on page 112, why did we write `mid=beg+(end-beg)/2;` instead of `mid=(beg+end) /2;`? @@ -108,7 +140,8 @@ Because the iterator of vector don't define the `+` operator **between the two i We can only use the subtraction between the two iterators. -##Exercise 3.27 +## Exercise 3.27 + >Assuming txt_size is a function that takes no arguments and returns an int value, which of the following definitions are illegal? Explain why. @@ -122,7 +155,8 @@ int ia[txt_size()]; // illegal, The dimension value must be a constant expressio char st[11] = "fundamental"; // illegal, the string's size is 12. ``` -##Exercise 3.28 +## Exercise 3.28 + >What are the values in the following arrays? ```cpp @@ -144,14 +178,17 @@ value is **undefined**. You can also use gdb to debug the value when the code is running. -##Exercise 3.29: +## Exercise 3.29 + >List some of the drawbacks of using an array instead of a vector. 1. can't add elements to an array. -2. vector is better supported bt std. +1. vector is better supported bt std. + +## Exercise 3.30 -##Exercise 3.30 >Identify the indexing errors in the following code: + ```cpp constexpr size_t array_size = 10; int ia[array_size]; @@ -162,32 +199,37 @@ for (size_t ix = 1; ix <= array_size; ++ix) The size of ia is 10, so the index of value should less than 10. ix **cannot** equal the array_size. -##[Exercise 3.31](ex3_31.cpp) -##[Exercise 3.32](ex3_32.cpp) -##Exercise 3.33 +## [Exercise 3.31](ex3_31.cpp) + +## [Exercise 3.32](ex3_32.cpp) + +## Exercise 3.33 + >What would happen if we did not initialize the scores array in the program on page 116? If we did not initialize the scores array. the array is undefined. the value will be Unknown. -Look like this: +## Exercise 3.34 -![result](https://db.tt/3T4TQoo8) - -##Exercise 3.34 >Given that p1 and p2 point to elements in the same array, what does the following code do? Are there values of p1 or p2 that make this code illegal? + ```cpp p1 += p2 - p1; ``` `p1 += p2 - p1;` same as `p1 = p2;`. If p2 and p1 are legal, this code always legal. -##[Exercise 3.35](ex3_35.cpp) -##[Exercise 3.36](ex3_36.cpp) -##Exercise 3.37 +## [Exercise 3.35](ex3_35.cpp) + +## [Exercise 3.36](ex3_36.cpp) + +## Exercise 3.37 + >What does the following program do? + ```cpp const char ca[] = {'h', 'e', 'l', 'l', 'o'}; const char *cp = ca; @@ -197,12 +239,12 @@ while (*cp) { } ``` -Print all the elements of the array. +Print all the elements of the array. ----- -**WARNING!!!!** -When we use a string, the compiler put it in the section `.rodata`, the code uses C-style character string without adding a '\0' in the end of `ca`. -So, when we code like this: +**WARNING!!!!** +When we use a string, the compiler put it in the section `.rodata`, the code uses C-style character string without adding a '\0' in the end of `ca`. +So, when we code like this: ```cpp const char ca[] = {'h', 'e', 'l', 'l', 'o'}; @@ -215,41 +257,50 @@ cout << *cp; ``` The code will print "helloworld" when you run it. -because the character list in the `.rodata` like this: +because the character list in the `.rodata` like this: + + h e l l o w o r l d \0 +`While(*cp)` judge weather *cp is 0 or not. when *cp is not 0, it will print the character until 0. +When you change the code like this: - h e l l o w o r l d \0 -`While(*cp)` judge weather *cp is 0 or not. when *cp is not 0, it will print the character until 0. -When you change the code like this: + const char ca[] = {'h', 'e', 'l', 'l', 'o', '\0'}; +the character list in the `.rodata`: - const char ca[] = {'h', 'e', 'l', 'l', 'o', '\0'}; -the character list in the `.rodata`: + h e l l o \0 w o r l d \0 +The program will run correctly. So when using C-style character string, be careful!! - h e l l o \0 w o r l d \0 -The program will run correctly. So when using C-style character string, be careful!! +----- ----- see `.rodata`, you can use this command: hexdump -C a.out -##Exercise 3.38 +## Exercise 3.38 + >In this section, we noted that it was not only illegal but meaningless to try to add two pointers. Why would adding two pointers be meaningless? - Because Subtracting two points gives a logically explainable result - the offset in memory between two points. Similarly, you can subtract or add an integral number to/from a pointer, which means "move the pointer up or down". Adding a pointer to a pointer is something which is hard to explain. The result is meaningless. ----- +----- + References: + - [Why can't I add pointers](http://stackoverflow.com/questions/2935038/why-cant-i-add-pointers) -##[Exercise 3.39](ex3_39.cpp) -##[Exercise 3.40](ex3_40.cpp) -##[Exercise 3.41](ex3_41.cpp) -##[Exercise 3.42](ex3_42.cpp) -##[Exercise 3.43](ex3_43.cpp) -##[Exercise 3.44](ex3_44.cpp) -##[Exercise 3.45](ex3_45.cpp) +## [Exercise 3.39](ex3_39.cpp) + +## [Exercise 3.40](ex3_40.cpp) + +## [Exercise 3.41](ex3_41.cpp) + +## [Exercise 3.42](ex3_42.cpp) + +## [Exercise 3.43](ex3_43.cpp) + +## [Exercise 3.44](ex3_44.cpp) + +## [Exercise 3.45](ex3_45.cpp) diff --git a/ch05/README.md b/ch05/README.md index 28751d7d..3fbdc4ac 100644 --- a/ch05/README.md +++ b/ch05/README.md @@ -1,24 +1,31 @@ -##Exercise 5.1 +# Chapter 5. Statements + +## Exercise 5.1 + >What is a null statement? When might you use a null statement? null statement is the empty statement. like this: + ```cpp ; // null statement ``` I might use a null statement when the language requires a statement but the program's logic does not. For example: + ```cpp // read until we hit end-of-file or find an input equal to sought while (cin >> s && s != sought) ; // null statement. ``` -##Exercise 5.2 +## Exercise 5.2 + >What is a block? When might you might use a block? block is a (possiby empty) sequence of statements and declarations surrounded by a pair of curly braces. I might use a block when the language requires a single statement but the logic of our program needs more than one. For example: + ```cpp while (val <= 10) { @@ -27,7 +34,8 @@ while (val <= 10) } ``` -##Exercise 5.3 +## Exercise 5.3 + >Use the comma operator (§ 4.10, p. 157) to rewrite the while loop from § 1.4.1 (p. 11) so that it no longer requires a block. Explain whether this rewrite improves or diminishes the readability of this code. @@ -49,31 +57,40 @@ int main() This rewrite diminishes the readability of the code. The comma operator always guarantees the order and discards the front result. But there are no meaning in this example, however, also are incomprehensible. -##Exercise 5.4 +## Exercise 5.4 + >Explain each of the following examples, and correct any problems you detect. -- (a) while (string::iterator iter != s.end()) { /* . . . */ } -- (b) while (bool status = find(word)) { /* . . . */ } -if (!status) { /* . . . */ } +> ```cpp +> - (a) while (string::iterator iter != s.end()) { /* . . . */ } +> - (b) while (bool status = find(word)) { /* . . . */ } +> if (!status) { /* . . . */ } +> ``` (a) iter point at nothing. invalid. + ```cpp std::string::iterator iter = s.begin(); while (iter != s.end()) { /* . . . */ } ``` (b) The if statement is not in the while's block. so the `status` is invalid. And if find(word) return true, it will go through the while block. we should declare the status before while. + ```cpp bool status; while ((status = find(word))) {/* ... */} if (!status) {/* ... */} -``` +``` In fact, the judge `!status` is unnecessary. If the `status=false`, we leave the while, and `!status` is always true. -##[Exercise 5.5](ex5_05.cpp) -##[Exercise 5.6](ex5_06.cpp) -##Exercise 5.7 +## [Exercise 5.5](ex5_05.cpp) + +## [Exercise 5.6](ex5_06.cpp) + +## Exercise 5.7 + >Correct the errors in each of the following code fragments: + ```cpp (a) if (ival1 != ival2) ival1 = ival2 else ival1 = ival2 = 0; @@ -104,18 +121,24 @@ In fact, the judge `!status` is unnecessary. If the `status=false`, we leave the ival = get_value(); ``` -##Exercise 5.8 +## Exercise 5.8 + >What is a “dangling else”? How are else clauses resolved in C++? Colloquial term used to refer to the problem of how to process nested if statements in which there are more ifs than elses. In C++, an else is always paired with the closest preceding unmatched if. -##[Exercise 5.9](ex5_09.cpp) -##[Exercise 5.10](ex5_10.cpp) -##[Exercise 5.11](ex5_11.cpp) -##[Exercise 5.12](ex5_12.cpp) +## [Exercise 5.9](ex5_09.cpp) + +## [Exercise 5.10](ex5_10.cpp) + +## [Exercise 5.11](ex5_11.cpp) + +## [Exercise 5.12](ex5_12.cpp) + +## Exercise 5.13 -##Exercise 5.13 >Each of the programs in the highlighted text on page 184 contains a common programming error. Identify and correct each error. + ```cpp (a) unsigned aCnt = 0, eCnt = 0, iouCnt = 0; char ch = next_text(); @@ -210,18 +233,22 @@ Colloquial term used to refer to the problem of how to process nested if stateme ``` ## Exercise 5.14 + >Write a program to read strings from standard input looking for duplicated words. The program should find places in the input where one word is followed immediately by itself. Keep track of the largest number of times a single repetition occurs and which word is repeated. Print the maximum number of duplicates, or else print a message saying that no word was repeated. For example, if the input is + ```sh how now now now brown cow cow ``` + the output should indicate that the word now occurred three times. - [concise solution](ex5_14.cpp) - [easy to understand](ex5_14_1.cpp) +## Exercise 5.15 -##Exercise 5.15 >Explain each of the following loops. Correct any problems you detect. + ```cpp (a) for (int ix = 0; ix != sz; ++ix) { /* ... */ } if (ix != sz) @@ -241,7 +268,8 @@ the output should indicate that the word now occurred three times. (c) for (int ix = 0; ix != sz; ++ix) { /*...*/ } ``` -##Exercise 5.16 +## Exercise 5.16 + >The while loop is particularly good at executing while some condition holds; for example, when we need to read values until end-of-file. The for loop is generally thought of as a **step loop**: An index steps through a range of values in a collection. Write an idiomatic use of each loop and then rewrite each using the other loop construct. If you could use only one loop, which would you choose? Why? ```cpp @@ -269,10 +297,12 @@ while (i != size) I prefer `for` to `while` in such cases, because it's terse. More importantly, object i won't pollute the external scope after it goes out of the loop. It's a little bit easier to add new code into the external scope, since it reduces the possibility of naming conflicts .That is, a higher maintainability. Of course, this way makes the code a bit harder to read. ([@Mooophy](https://github.com/Mooophy)) -##[Exercise 5.17](ex5_17.cpp) +## [Exercise 5.17](ex5_17.cpp) + +## Exercise 5.18 -##Exercise 5.18 >Explain each of the following loops. Correct any problems you detect. + ```cpp (a) do { // added bracket. int v1, v2; @@ -290,14 +320,18 @@ I prefer `for` to `while` in such cases, because it's terse. More importantly, o } while (ival); // ival is not declared in this scope. ``` -##[Exercise 5.19](ex5_19.cpp) -##[Exercise 5.20](ex5_20.cpp) -##[Exercise 5.21](ex5_21.cpp) +## [Exercise 5.19](ex5_19.cpp) + +## [Exercise 5.20](ex5_20.cpp) + +## [Exercise 5.21](ex5_21.cpp) + +## Exercise 5.22 -##Exercise 5.22 >The last example in this section that jumped back to begin could be better written using a loop. Rewrite the code to eliminate the goto. + ```cpp -// backward jump over an initialized variable definition is okay +// backward jump over an initialized variable definition is okay begin: int sz = get_size(); if (sz <= 0) { @@ -306,11 +340,14 @@ begin: ``` use `for` to replace `goto`: + ```cpp for (int sz = get_size(); sz <=0; sz = get_size()) ; // should not remove. ``` -##[Exercise 5.23](ex5_23.cpp) -##[Exercise 5.24](ex5_24.cpp) -##[Exercise 5.25](ex5_25.cpp) +## [Exercise 5.23](ex5_23.cpp) + +## [Exercise 5.24](ex5_24.cpp) + +## [Exercise 5.25](ex5_25.cpp) diff --git a/ch06/README.md b/ch06/README.md index 27411592..006d83dc 100644 --- a/ch06/README.md +++ b/ch06/README.md @@ -1,11 +1,13 @@ -##Exercise 6.1 +# Chapter 6. Functions + +## Exercise 6.1 **Parameters**: Local variable declared inside the function parameter list. they are initialized by the **arguments** provided in the each function call. **Arguments**: Values supplied in a function call that are used to initialize the function's **parameters**. -##Exercise 6.2 +## Exercise 6.2 ```cpp (a) string f() { @@ -18,7 +20,7 @@ they are initialized by the **arguments** provided in the each function call. (d) double square (double x) { return x * x; } ``` -##Exercise 6.3 +## Exercise 6.3 ```cpp #include @@ -39,7 +41,7 @@ int main() ## [Exercise 6.4](ex6_04.cpp) -##Exercise 6.5 +## Exercise 6.5 ```cpp template @@ -49,8 +51,7 @@ T abs(T i) } ``` -##Exercise 6.6 - +## Exercise 6.6 **local variable**: Variables defined inside a **block**; @@ -87,10 +88,15 @@ size_t generate() ``` ## [Exercise 6.8](Chapter6.h) + ## Exercise 6.9 [fact.cc](fact.cc) | [factMain.cc](factMain.cc) + ## [Exercise 6.10](ex6_10.cpp) + ## [Exercise 6.11](ex6_11.cpp) + ## [Exercise 6.12](ex6_12.cpp) + ## Exercise 6.13 `void f(T)` pass the argument by value. **nothing the function does to the parameter can affect the argument**. @@ -99,6 +105,7 @@ size_t generate() ## Exercise 6.14 a parameter should be a reference type: + ```cpp void reset(int &i) { @@ -107,6 +114,7 @@ void reset(int &i) ``` a parameter should not be a reference: + ```cpp void print(std::vector::iterator begin, std::vector::iterator end) { @@ -123,13 +131,14 @@ cause the `s` should not be changed by this function. but `occurs`'s result must >Why are these parameters references, but the char parameter `c` is not? -It's OK to use const reference here but copying a `char` directly would be more memory-efficient. +It's OK to use const reference here but copying a `char` directly would be more memory-efficient. >What would happen if we made `s` a plain reference? What if we made `occurs` a reference to const? `s` could be changed in the function, and `occurs` would not be changed. so `occurs = 0;` is an error. ## Exercise 6.16 + ```cpp bool is_empty(const string& s) { return s.empty(); } ``` @@ -146,11 +155,15 @@ For the second function,"const" can't be used,because the content of the agument should be changed. ## Exercise 6.18 + (a) + ```cpp bool compare(const matrix &m1, const matrix &m2){ /.../ } ``` + (b) + ```cpp vector::iterator change_val(int, vector::iterator) { /.../ } ``` @@ -168,7 +181,9 @@ If we can use `const`, just use it. If we make a parameter a plain reference whe the reference value maybe changed. ## [Exercise 6.21](ex6_21.cpp) + ## [Exercise 6.22](ex6_22.cpp) + ## [Exercise 6.23](ex6_23.cpp) ## Exercise 6.24 @@ -180,13 +195,15 @@ to the array's first element. In this question, `const int ia[10]` is actually same as `const int*`, and the size of the array is **irrelevant**. we can pass `const int ia[3]` or `const int ia[255]`, there are no differences. If we want to pass an array which size is ten, we should use reference like that: + ```cpp void print10(const int (&ia)[10]) { /*...*/ } ``` -see more discusses at http://stackoverflow.com/questions/26530659/confused-about-array-parameters +see more discusses at ## [Exercise 6.25 && Exercise 6.26](ex6_25_26.cpp) + ## [Exercise 6.27](ex6_27.cpp) ## Exercise 6.28 @@ -200,10 +217,9 @@ Depends on the type of elements of `initializer_list`. When the type is [PODType ## Exercise 6.30 Error (Clang): ->Non-void function 'str_subrange' should return a value. // error #1 - - ->Control may reach end of non-void function. // error #2 +> Non-void function 'str_subrange' should return a value. // error #1 +> +> Control may reach end of non-void function. // error #2 ## Exercise 6.31 @@ -213,7 +229,8 @@ when you can find the preexited object that the reference refered. legal, it gave the values (0 ~ 9) to array `ia`. -##[Exercise 6.33](ex6_33.cpp)([Generics Version](ex6_33_generics_version.cpp)) +## [Exercise 6.33](ex6_33.cpp)([Generics Version](ex6_33_generics_version.cpp)) + ## Exercise 6.34 When the recursion termination condition becomes `var != 0`, two situations can happen : @@ -245,6 +262,7 @@ decltype(arrS)& func3(ArrT& arr); I pefer the first one. because it is more simpler to me. ## Exercise 6.38 + ```cpp decltype(arrStr)& arrPtr(int i) { @@ -275,16 +293,19 @@ decltype(arrStr)& arrPtr(int i) (c) legal, but not match. `wd` would be setting to '*'. ## [Exercise 6.42](ex6_42.cpp) + ## Exercise 6.43 Both two should put in a header. (a) is an inline function. (b) is the declaration of useful function. we always put them in the header. ## [Exercise 6.44](ex6_44.cpp) + ## Exercise 6.45 For example, the function `arrPtr` in [Exercise 6.38](#exercise-638) and `make_plural` in [Exercise 6.42](#exercise-642) should be defined as `inline`. But the function `func` in [Exercise 6.4](#exercise-64) shouldn't. Cause it just being call once and too many codes in the function. ## Exercise 6.46 + > Would it be possible to define `isShorter` as a `constexpr`? If so, do so. If not, explain why not. No. @@ -296,6 +317,7 @@ But `std::string`(parameter of `isShorter`) is not a literal type. more discusses: [#22](https://github.com/ReadingLab/Discussion-for-Cpp/issues/22) ## [Exercise 6.47](ex6_47.cpp) + ## Exercise 6.48 This loop let user input a word all the way until the word is sought. @@ -324,6 +346,7 @@ viable function: (d) match `void f(double, double = 3.14)`. ## [Exercise 6.51](ex6_51.cpp) + ## Exercise 6.52 (a) Match through a promotion @@ -333,20 +356,25 @@ viable function: ## Exercise 6.53 (a) + ```cpp int calc(int&, int&); // calls lookup(int&) int calc(const int&, const int&); // calls lookup(const int&) ``` + (b) + ```cpp int calc(char*, char*); // calls lookup(char*) int calc(const char*, const char*); //calls lookup(const char *) ``` + (c) illegal. both calls lookup(char*) ## Exercise 6.54 + ```cpp int func(int a, int b); @@ -366,6 +394,7 @@ std::vector vec6; ``` ## Exercise 6.55 + ```cpp int add(int a, int b) { return a + b; } int subtract(int a, int b) { return a - b; } @@ -374,6 +403,7 @@ int divide(int a, int b) { return b != 0 ? a / b : 0; } ``` ## Exercise 6.56 + ```cpp std::vector vec{add, subtract, multiply, divide}; for (auto f : vec) diff --git a/ch07/README.md b/ch07/README.md index 94e1ed1d..91998fad 100644 --- a/ch07/README.md +++ b/ch07/README.md @@ -1,36 +1,28 @@ -[Exercise 7.1](ex7_01.cpp) --------------------------- +# Chapter 7. Classes -[Exercise 7.2](ex7_02.h) ------------------------- +## [Exercise 7.1](ex7_01.cpp) -[Exercise 7.3](ex7_03.cpp) --------------------------- +## [Exercise 7.2](ex7_02.h) -[Exercise 7.4](ex7_04.h) ------------------------- +## [Exercise 7.3](ex7_03.cpp) -[Exercise 7.5](ex7_05.h) ------------------------- +## [Exercise 7.4](ex7_04.h) -[Exercise 7.6](ex7_06.h) ------------------------- +## [Exercise 7.5](ex7_05.h) -[Exercise 7.7](ex7_07.cpp) --------------------------- +## [Exercise 7.6](ex7_06.h) -Exercise 7.8 ------------- +## [Exercise 7.7](ex7_07.cpp) + +## Exercise 7.8 Define `read`'s `Sales_data` parameter as plain reference since it's intended to change the `revenue`'s value. Define `print`'s `Sales_data` parameter as a reference to `const` since it isn't intended to change any member's value of this object. -[Exercise 7.9](ex7_09.h) ------------------------- +## [Exercise 7.9](ex7_09.h) -Exercise 7.10 -------------- +## Exercise 7.10 ```cpp if(read(read(cin, data1), data2)) @@ -46,27 +38,21 @@ if (secondStep) the condition of the `if` statement would read two `Sales_data` object at one time. -Exercise 7.11 [Header](ex7_11.h)|[CPP](ex7_11.cpp) --------------------------------------------------- +## Exercise 7.11 [Header](ex7_11.h)|[CPP](ex7_11.cpp) -[Exercise 7.12](ex7_12.h) -------------------------- +## [Exercise 7.12](ex7_12.h) -[Exercise 7.13](ex7_13.cpp) ---------------------------- +## [Exercise 7.13](ex7_13.cpp) -Exercise 7.14 -------------- +## Exercise 7.14 ```cpp Sales_data() : units_sold(0) , revenue(0){} ``` -[Exercise 7.15](ex7_15.h) -------------------------- +## [Exercise 7.15](ex7_15.h) -Exercise 7.16 -------------- +## Exercise 7.16 There are no restrictions on how often an access specifier may appear.The specified access level remains in effect until the next access specifier or the end of the class body. @@ -74,13 +60,11 @@ The members which are accessible to all parts of the program should define after The members which are accessible to the member functions of the class but are not accessible to code that uses the class should define after a private specifier. -Exercise 7.17 -------------- +## Exercise 7.17 The only difference between using `class` and using `struct` to define a class is the default access level. (`class` : private, `struct` : public) -Exercise 7.18 -------------- +## Exercise 7.18 encapsulation is the separation of implementation from interface. It hides the implementation details of a type. (In C++, encapsulation is enforced by putting the implementation in the private part of a class) @@ -88,47 +72,40 @@ encapsulation is the separation of implementation from interface. It hides the i Important advantages: -- User code cannot inadvertently corrupt the state of an encapsulation object. -- The implementation of an encapsulated class can change over time without requiring changes in user-level code. +- User code cannot inadvertently corrupt the state of an encapsulation object. +- The implementation of an encapsulated class can change over time without requiring changes in user-level code. -Exercise 7.19 -------------- +## Exercise 7.19 -- `public` include: constructors, `getName()`, `getAddress()`. -- `private` include: `name`, `address`. +- `public` include: constructors, `getName()`, `getAddress()`. +- `private` include: `name`, `address`. the interface should be defined as public, the data shouldn't expose to outside of the class. -Exercise 7.20 -------------- +## Exercise 7.20 `friend` is a mechanism by which a class grants access to its nonpublic members. They have the same rights as members. **Pros**: -- the useful functions can refer to class members in the class scope without needing to explicitly prefix them with the class name. -- you can access all the nonpublic members conveniently. -- sometimes, more readable to the users of class. +- the useful functions can refer to class members in the class scope without needing to explicitly prefix them with the class name. +- you can access all the nonpublic members conveniently. +- sometimes, more readable to the users of class. **Cons**: -- lessens encapsulation and therefore maintainability. -- code verbosity, declarations inside the class, outside the class. +- lessens encapsulation and therefore maintainability. +- code verbosity, declarations inside the class, outside the class. -[Exercise 7.21](ex7_21.h) -------------------------- +## [Exercise 7.21](ex7_21.h) -[Exercise 7.22](ex7_22.h) -------------------------- +## [Exercise 7.22](ex7_22.h) -Exercise 7.23 [Header](ex7_23.h)|[CPP](ex7_23.cpp) --------------------------------------------------- +## Exercise 7.23 [Header](ex7_23.h)|[CPP](ex7_23.cpp) -[Exercise 7.24](ex7_24.h) -------------------------- +## [Exercise 7.24](ex7_24.h) -Exercise 7.25 -------------- +## Exercise 7.25 The class below can rely on it. It goes in *Section 7.1.5*: @@ -138,19 +115,15 @@ The class below can rely on it. It goes in *Section 7.1.5*: Hence the class below which used only built-in type and strings can rely on the default version of copy and assignment. (by [@Mooophy](https://github.com/Mooophy)\) -Exercise 7.26 [Header](ex7_26.h)|[CPP](ex7_26.cpp) --------------------------------------------------- +## Exercise 7.26 [Header](ex7_26.h)|[CPP](ex7_26.cpp) -Exercise 7.27 [Class](ex7_27.h)|[Test](ex7_27_TEST.cpp) -------------------------------------------------------- +## Exercise 7.27 [Class](ex7_27.h)|[Test](ex7_27_TEST.cpp) -Exercise 7.28 -------------- +## Exercise 7.28 The second call to `display` couldn't print `#` among the output, cause the call to `set` would change the **temporary copy**, not myScreen. -Exercise 7.29 -------------- +## Exercise 7.29 ```sh #with '&' @@ -163,36 +136,32 @@ XXXXXXXXXXXXXXXXXXXXXXXXX ^^^ ``` -Exercise 7.30 -------------- +## Exercise 7.30 -**Pros** +### Pros -- more explicit -- less scope for misreading -- can use the member function parameter which name is same as the member name. +- more explicit +- less scope for misreading +- can use the member function parameter which name is same as the member name. - ```cpp - void setAddr(const std::string &addr) {this->addr = addr;} - ``` +```cpp +void setAddr(const std::string &addr) {this->addr = addr;} +``` -**Cons** +### Cons -- more to read -- sometimes redundant +- more to read +- sometimes redundant - ```cpp - std::string getAddr() const { return this->addr; } // unnecessary - ``` +```cpp +std::string getAddr() const { return this->addr; } // unnecessary +``` -[Exercise 7.31](ex7_31.h) -------------------------- +## [Exercise 7.31](ex7_31.h) -[Exercise 7.32](ex7_32.h) -------------------------- +## [Exercise 7.32](ex7_32.h) -Exercise 7.33 -------------- +## Exercise 7.33 [clang]error: unknown type name 'pos' @@ -205,8 +174,7 @@ Screen::pos Screen::size() const } ``` -Exercise 7.34 -------------- +## Exercise 7.34 There is an error in @@ -216,8 +184,7 @@ dummy_fcn(pos height) Unknown type name 'pos' ``` -Exercise 7.35 -------------- +## Exercise 7.35 ```cpp typedef string Type; @@ -237,7 +204,7 @@ Type Exercise::setVal(Type parm) { // first is `string`, second is `double` } ``` -**fixed** +### fixed changed @@ -259,12 +226,11 @@ Exercise::Type Exercise::setVal(Type parm) { and `Exercise::initVal()` should be defined. -Exercise 7.36 -------------- +## Exercise 7.36 > In this case, the constructor initializer makes it appear as if `base` is initialized with `i` and then `base` is used to initialize `rem`. However, `base` is initialized first. The effect of this initializer is to initialize `rem` with the undefined value of `base`! -**fixd** +### fixd ```cpp struct X { @@ -273,8 +239,7 @@ struct X { }; ``` -Exercise 7.37 -------------- +## Exercise 7.37 ```cpp Sales_data first_item(cin); // use Sales_data(std::istream &is) ; its value are up to your input. @@ -285,20 +250,17 @@ int main() { } ``` -Exercise 7.38 -------------- +## Exercise 7.38 ```cpp Sales_data(std::istream &is = std::cin) { read(is, *this); } ``` -Exercise 7.39 -------------- +## Exercise 7.39 illegal. cause the call of overloaded 'Sales_data()' is **ambiguous**. -Exercise 7.40 -------------- +## Exercise 7.40 Such as `Book`: @@ -317,11 +279,9 @@ private: }; ``` -Exercise 7.41 [Header](ex7_41.h)|[CPP](ex7_41.cpp)|[Test](ex7_41_TEST.cpp) --------------------------------------------------------------------------- +## Exercise 7.41 [Header](ex7_41.h)|[CPP](ex7_41.cpp)|[Test](ex7_41_TEST.cpp) -Exercise 7.42 -------------- +## Exercise 7.42 ```cpp class Book { @@ -338,52 +298,45 @@ private: }; ``` -[Exercise 7.43](ex7_43.cpp) ---------------------------- +## [## Exercise 7.43](ex7_43.cpp) -Exercise 7.44 -------------- +## Exercise 7.44 illegal, cause there are ten elements, each would be value initialized. But no default constructor for `NoDefault` type. -Exercise 7.45 -------------- +## Exercise 7.45 No problem. cause `C` have the default constructor. -Exercise 7.46 -------------- +## Exercise 7.46 -- a) A class must provide at least one constructor. (**untrue**, "The compiler-generated constructor is known as the synthesized default constructor.") -- b) A default constructor is a constructor with an empty parameter list. (**untrue**, A default constructor is a constructor that is used if no initializer is supplied.What's more, A constructor that supplies default arguments for all its parameters also defines the default constructor) -- c) If there are no meaningful default values for a class, the class should not provide a default constructor. (**untrue**, the class should provide.) -- d) If a class does not define a default constructor, the compiler generates one that initializes each data member to the default value of its associated type. (**untrue**, only if our class does not explicitly define **any constructors**, the compiler will implicitly define the default constructor for us.) +- a) A class must provide at least one constructor. (**untrue**, "The compiler-generated constructor is known as the synthesized default constructor.") +- b) A default constructor is a constructor with an empty parameter list. (**untrue**, A default constructor is a constructor that is used if no initializer is supplied.What's more, A constructor that supplies default arguments for all its parameters also defines the default constructor) +- c) If there are no meaningful default values for a class, the class should not provide a default constructor. (**untrue**, the class should provide.) +- d) If a class does not define a default constructor, the compiler generates one that initializes each data member to the default value of its associated type. (**untrue**, only if our class does not explicitly define **any constructors**, the compiler will implicitly define the default constructor for us.) -Exercise 7.47 -------------- +## Exercise 7.47 Whether the conversion of a `string` to `Sales_data` is desired **depends on how we think our users will use the conversion**. In this case, it might be okay. The `string` in null_book probably represents a nonexistent ISBN. Benefits: -- prevent the use of a constructor in a context that requires an implicit conversion -- we can define a constructor which is used only with the direct form of initialization +- prevent the use of a constructor in a context that requires an implicit conversion +- we can define a constructor which is used only with the direct form of initialization Drawbacks: -- meaningful only on constructors that can be called with a single argument +- meaningful only on constructors that can be called with a single argument -Exercise 7.48 -------------- +## Exercise 7.48 Both are noting happened. -Exercise 7.49 -------------- +## Exercise 7.49 ```cpp (a) Sales_data &combine(Sales_data); // ok -(b) Sales_data &combine(Sales_data&); // [Error] no matching function for call to 'Sales_data::combine(std::string&)' (`std::string&` can not convert to `Sales_data` type.) +(b) Sales_data &combine(Sales_data&); // [Error] no matching function for call to 'Sales_data::combine(std::string&)' (`std::string&` can not convert to `Sales_data` type.) (c) Sales_data &combine(const Sales_data&) const; // The trailing const mark can't be put here, as it forbids any mutation on data members. This conflicts with combines semantics. ``` @@ -393,11 +346,9 @@ It's wrong. Because `combine`’s parameter is a non-const reference , we can't pass a temporary to that parameter. If `combine`’s parameter is a reference to `const` , we can pass a temporary to that parameter. Like this :`Sales_data &combine(const Sales_data&);` Here we call the `Sales_data` `combine` member function with a string argument. This call is perfectly legal; the compiler automatically creates a `Sales_data` object from the given string. That newly generated (temporary) `Sales_data` is passed to `combine`.(check on page 295(English Edition)) -[Exercise 7.50](ex7_50.h) -------------------------- +## [Exercise 7.50](ex7_50.h) -Exercise 7.51 -------------- +## Exercise 7.51 Such as a function like that: @@ -422,8 +373,7 @@ setYourName("pezy"); // just fine. it is very natural. -Exercise 7.52 -------------- +## Exercise 7.52 In my opinion ,the aim of the problem is Aggregate Class. Test-makers think that `Sales_data` is Aggregate Class,so `Sales_data` should have no in-class initializers if we want to initialize the data members of an aggregate class by providing a braced list of member initializers: @@ -437,16 +387,13 @@ struct Sales_data { }; ``` -[Exercise 7.53](ex7_53.h) -------------------------- +## [## Exercise 7.53](ex7_53.h) -Exercise 7.54 -------------- +## Exercise 7.54 shouldn't, cause a `constexpr` function must contain exactly one **return** statement. -Exercise 7.55 -------------- +## Exercise 7.55 no. @@ -470,8 +417,7 @@ int main() } ``` -Exercise 7.56 -------------- +## Exercise 7.56 > What is a static class member? @@ -483,14 +429,12 @@ each object can no need to store a common data. And if the data is changed, each > How do they differ from ordinary members? -- a static data member can have **incomplete type**. -- we can use a static member **as a default argument**. +- a static data member can have **incomplete type**. +- we can use a static member **as a default argument**. -[Exercise 7.57](ex7_57.h) -------------------------- +## [Exercise 7.57](ex7_57.h) -Exercise 7.58 -------------- +## Exercise 7.58 ```cpp static double rate = 6.5; diff --git a/ch08/README.md b/ch08/README.md index c136c5a8..97e93382 100644 --- a/ch08/README.md +++ b/ch08/README.md @@ -1,6 +1,7 @@ # Chapter 8. The IO Library -## Exercise 8.1: +## Exercise 8.1 + >Write a function that takes and returns an istream&. The function should read the stream until it hits end-of-file. The function should print what it reads to the standard output. Reset the stream so that it is valid before returning the stream. ```cpp @@ -16,8 +17,10 @@ istream& func(istream &is) ## [Exercise 8.2](ex8_02.cpp) -## Exercise 8.3: +## Exercise 8.3 + >What causes the following while to terminate? + ```cpp while (cin >> i) /* ... */ ``` @@ -25,22 +28,31 @@ while (cin >> i) /* ... */ putting `cin` in an error state cause to terminate. such as `eofbit`, `failbit` and `badbit`. ## [Exercise 8.4](ex8_04.cpp) + ## [Exercise 8.5](ex8_05.cpp) + ## [Exercise 8.6](ex8_06.cpp) + ## [Exercise 8.7](ex8_07.cpp) + ## [Exercise 8.8](ex8_08.cpp) + ## [Exercise 8.9](ex8_09.cpp) + ## [Exercise 8.10](ex8_10.cpp) + ## [Exercise 8.11](ex8_11.cpp) -## Exercise 8.12: +## Exercise 8.12 + >Why didn’t we use in-class initializers in PersonInfo? Cause we need a aggregate class here. so it should have no in-class initializers. ## [Exercise 8.13](ex8_13.cpp) -## Exercise 8.14: +## Exercise 8.14 + >Why did we declare entry and nums as const auto &? - cause they are all class type, not the built-in type. so **reference** more effective. diff --git a/ch10/README.md b/ch10/README.md index 94bb1dee..89f2879f 100644 --- a/ch10/README.md +++ b/ch10/README.md @@ -1,23 +1,16 @@ -Chapter 10. Generic Algorithms -============================== +# Chapter 10. Generic Algorithms -[Exercise 10.1 and 10.2](ex10_01_02.cpp) ----------------------------------------- +## [Exercise 10.1 and 10.2](ex10_01_02.cpp) -[Exercise 10.3 and 10.4](ex10_03_04.cpp) ----------------------------------------- +## [Exercise 10.3 and 10.4](ex10_03_04.cpp) -[Exercise 10.5](ex10_05.cpp) ----------------------------- +## [Exercise 10.5](ex10_05.cpp) -[Exercise 10.6](ex10_06.cpp) ----------------------------- +## [Exercise 10.6](ex10_06.cpp) -[Exercise 10.7](ex10_07.cpp) ----------------------------- +## [Exercise 10.7](ex10_07.cpp) -Exercise 10.8: --------------- +## Exercise 10.8 > We said that algorithms do not change the size of the containers over which they operate. Why doesn’t the use of back_inserter invalidate this claim? @@ -25,11 +18,9 @@ Cause the `back_inserter` is a **insert iterator**, what iterator adaptor that g the algorithms don't change the size, but the iterator can change it by using the container operation. -[Exercise 10.9](ex10_09.cpp) ----------------------------- +## [Exercise 10.9](ex10_09.cpp) -Exercise 10.10: ---------------- +## Exercise 10.10 > Why do you think the algorithms don’t change the size of containers? @@ -37,17 +28,13 @@ Exercise 10.10: @pezy: Cause the library algorithms operate on **iterators**, **not containers**. Thus, an algorithm **cannot (directly)** add or remove elements. -[Exercise 10.11](ex10_11.cpp) ------------------------------ +## [Exercise 10.11](ex10_11.cpp) -[Exercise 10.12](ex10_12.cpp) ------------------------------ +## [Exercise 10.12](ex10_12.cpp) -[Exercise 10.13](ex10_13.cpp) ------------------------------ +## [Exercise 10.13](ex10_13.cpp) -Exercise 10.14: ---------------- +## Exercise 10.14 > Write a lambda that takes two ints and returns their sum. @@ -55,8 +42,7 @@ Exercise 10.14: auto add = [](int lhs, int rhs){return lhs + rhs;}; ``` -Exercise 10.15: ---------------- +## Exercise 10.15 > Write a lambda that captures an int from its enclosing function and takes an int parameter. The lambda should return the sum of the captured int and the int parameter. @@ -65,99 +51,77 @@ int i = 42; auto add = [i](int num){return i + num;}; ``` -[Exercise 10.16](ex10_16.cpp) ------------------------------ +## [Exercise 10.16](ex10_16.cpp) -[Exercise 10.17](ex10_17.cpp) ------------------------------ +## [Exercise 10.17](ex10_17.cpp) -[Exercise 10.18 and 10.19](ex10_18_19.cpp) ------------------------------------------- +## [Exercise 10.18 and 10.19](ex10_18_19.cpp) -[Exercise 10.20](ex10_20.cpp) ------------------------------ +## [Exercise 10.20](ex10_20.cpp) -[Exercise 10.21](ex10_21.cpp) ------------------------------ +## [Exercise 10.21](ex10_21.cpp) -[Exercise 10.22](ex10_22.cpp) ------------------------------ +## [Exercise 10.22](ex10_22.cpp) -Exercise 10.23: ---------------- +## Exercise 10.23 > How many arguments does bind take? Assuming the function to be bound have `n` parameters, bind take `n + 1` parameters. The additional one is for the function to be bind itself. -[Exercise 10.24](ex10_24.cpp) ------------------------------ +## [Exercise 10.24](ex10_24.cpp) -[Exercise 10.25](ex10_25.cpp) ------------------------------ +## [Exercise 10.25](ex10_25.cpp) -Exercise 10.26: ---------------- +## Exercise 10.26 > Explain the differences among the three kinds of insert iterators. -- `back_inserter` uses `push_back`. -- `front_inserter` uses `push_front`. -- `insert` uses `insert` >This function takes a second argument, which must be an iterator into the given container. Elements are inserted ahead of the element denoted by the given iterator. +- `back_inserter` uses `push_back`. +- `front_inserter` uses `push_front`. +- `insert` uses `insert` >This function takes a second argument, which must be an iterator into the given container. Elements are inserted ahead of the element denoted by the given iterator. -[Exercise 10.27](ex10_27.cpp) ------------------------------ +## [Exercise 10.27](ex10_27.cpp) -[Exercise 10.28](ex10_28.cpp) ------------------------------ +## [Exercise 10.28](ex10_28.cpp) -[Exercise 10.29](ex10_29.cpp) ------------------------------ +## [Exercise 10.29](ex10_29.cpp) -[Exercise 10.30](ex10_30.cpp) ------------------------------ +## [Exercise 10.30](ex10_30.cpp) -[Exercise 10.31](ex10_31.cpp) ------------------------------ +## [Exercise 10.31](ex10_31.cpp) -[Exercise 10.32](ex10_32.cpp) ------------------------------ +## [Exercise 10.32](ex10_32.cpp) -[Exercise 10.33](ex10_33.cpp) ------------------------------ +## [Exercise 10.33](ex10_33.cpp) -[Exercise 10.34 ~ 10.37](ex10_34_35_36_37.cpp) ----------------------------------------------- +## [Exercise 10.34 ~ 10.37](ex10_34_35_36_37.cpp) -Exercise 10.38: ---------------- +## Exercise 10.38 > List the five iterator categories and the operations that each supports. -- Input iterators : `==`, `!=`, `++`, `*`, `->` -- Output iterators : `++`, `*` -- Forward iterators : `==`, `!=`, `++`, `*`, `->` -- Bidirectional iterators : `==`, `!=`, `++`, `--`, `*`, `->` -- Random-access iterators : `==`, `!=`, `<`, `<=`, `>`, `>=`, `++`, `--`, `+`, `+=`, `-`, `-=`, `-`(two iterators), `*`, `->`, `iter[n]` == `* (iter + n)` +- Input iterators : `==`, `!=`, `++`, `*`, `->` +- Output iterators : `++`, `*` +- Forward iterators : `==`, `!=`, `++`, `*`, `->` +- Bidirectional iterators : `==`, `!=`, `++`, `--`, `*`, `->` +- Random-access iterators : `==`, `!=`, `<`, `<=`, `>`, `>=`, `++`, `--`, `+`, `+=`, `-`, `-=`, `-`(two iterators), `*`, `->`, `iter[n]` == `* (iter + n)` -Exercise 10.39: ---------------- +## Exercise 10.39 > What kind of iterator does a list have? What about a vector? `list` have the **Bidirectional iterators**. `vector` have the **Random-access iterators**. -Exercise 10.40: ---------------- +## Exercise 10.40 > What kinds of iterators do you think copy requires? What about reverse or unique? -- `copy` : first and second are Input iterators, last is Output iterators. -- `reverse` : Bidirectional iterators. -- `unique` : Forward iterators. +- `copy` : first and second are Input iterators, last is Output iterators. +- `reverse` : Bidirectional iterators. +- `unique` : Forward iterators. -Exercise 10.41: ---------------- +## Exercise 10.41 > Based only on the algorithm and argument names, describe the operation that the each of the following library algorithms performs: @@ -168,5 +132,4 @@ replace_copy(beg, end, dest, old_val, new_val); // copy the new_elements which i replace_copy_if(beg, end, dest, pred, new_val); // copy the new_elements which pred is true in the input range into dest. ``` -[Exercise 10.42](ex10_42.cpp) ------------------------------ +## [Exercise 10.42](ex10_42.cpp) diff --git a/ch11/README.md b/ch11/README.md index e9b675dd..6b238078 100644 --- a/ch11/README.md +++ b/ch11/README.md @@ -1,13 +1,15 @@ # Chapter 11. Associative Containers -## Exercise 11.1: +## Exercise 11.1 + >Describe the differences between a map and a vector. A `map` is a collection of key-value pairs. we can get a value **lookup by key** efficiently. A `vector` is a collection of objects, and every object has an **associated index**, which gives access to that object. -## Exercise 11.2: +## Exercise 11.2 + >Give an example of when each of list, vector, deque, map, and set might be most useful. - `list` : a to-do list. always need insert or delete the elements anywhere. @@ -18,7 +20,8 @@ A `vector` is a collection of objects, and every object has an **associated inde ## [Exercise 11.3 and 11.4](ex11_3_4.cpp) -## Exercise 11.5: +## Exercise 11.5 + >Explain the difference between a map and a set. When might you use one or the other? - `set` : the element type is the **key type**. @@ -26,26 +29,34 @@ A `vector` is a collection of objects, and every object has an **associated inde I use `set` when i just need to store the `key`, In other hand, I would like use `map` when i need to store a key-value pair. -## Exercise 11.6: +## Exercise 11.6 + >Explain the difference between a set and a list. When might you use one or the other? `set` is unique and order, but `list` is neither. using which one depend on whether the elements are unique and order to store. ## [Exercise 11.7](ex11_7.cpp) + ## [Exercise 11.8](ex11_8.cpp) + ## [Exercise 11.9 and 11.10](ex11_9_10.cpp) + ## [Exercise 11.11](ex11_11.cpp) + ## [Exercise 11.12 and 11.13](ex11_12_13.cpp) + ## [Exercise 11.14](ex11_14.cpp) -## Exercise 11.15: +## Exercise 11.15 + >What are the `mapped_type`, `key_type`, and `value_type` of a `map` from int to `vector`? - `mapped_type` : `vector` - `key_type` : `int` - `value_type` : `std::pair>` -## Exercise 11.16: +## Exercise 11.16 + >Using a map iterator write an expression that assigns a value to an element. ```cpp @@ -55,7 +66,8 @@ std::map::iterator it = map.begin(); it->second = "Wang"; ``` -## Exercise 11.17: +## Exercise 11.17 + >Assuming c is a multiset of strings and v is a vector of strings, explain the following calls. Indicate whether each call is legal: @@ -65,8 +77,11 @@ copy(v.begin(), v.end(), back_inserter(c)); // illegal, no `push_back` in `set`. copy(c.begin(), c.end(), inserter(v, v.end())); // legal. copy(c.begin(), c.end(), back_inserter(v)); // legal. ``` + ## [Exercise 11.18](ex11_18.cpp) -## Exercise 11.19: + +## Exercise 11.19 + >Define a variable that you initialize by calling begin() on the multiset named bookstore from 11.2.2 (p. 425). Write the variable’s type without using auto or decltype. @@ -75,9 +90,13 @@ using compareType = bool (*)(const Sales_data &lhs, const Sales_data &rhs); std::multiset bookstore(compareIsbn); std::multiset::iterator c_it = bookstore.begin(); ``` + ## [Exercise 11.20](ex11_20.cpp) -## Exercise 11.21: + +## Exercise 11.21 + >Assuming word_count is a map from string to size_t and word is a string, explain the following loop: + ```cpp while (cin >> word) ++word_count.insert({word, 0}).first->second; @@ -86,8 +105,10 @@ while (cin >> word) ```cpp ++ (word_count.insert({word, 0}).first->second) ``` -## Exercise 11.22: ->Given a map>, write the types used as an argument and as the return value for the version of insert that inserts one element. + +## Exercise 11.22 + +>Given a `map>`, write the types used as an argument and as the return value for the version of insert that inserts one element. ```cpp std::pair> // argument @@ -95,29 +116,40 @@ std::pair>::iterator, bool> // return ``` ## [Exercise 11.23](ex11_23.cpp) + ## [Exercise 11.24 ~ 11.26](ex11_24_25_26.cpp) + ## [Exercise 11.27 ~ 11.30](ex11_27_28_29_30.cpp) + ## [Exercise 11.31](ex11_31.cpp) + ## [Exercise 11.32](ex11_32.cpp) + ## [Exercise 11.33](ex11_33.cpp) -## Exercise 11.34: +## Exercise 11.34 + >What would happen if we used the subscript operator instead of find in the transform function? In gcc 4.8.3, will report error: + ```cpp error: passing ‘const std::map, std::basic_string >’ as ‘this’ argument of ‘std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const key_type&) [with _Key = std::basic_string; _Tp = std::basic_string; _Compare = std::less >; _Alloc = std::allocator, std::basic_string > >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = std::basic_string; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = std::basic_string]’ discards qualifiers [-fpermissive] auto key = m[s]; ^ ``` + Because std::map's operator is not declared as **const**,but m is declared as a reference to std::map with **const**.If insert new pair,it will cause error. -## Exercise 11.35: + +## Exercise 11.35 + >In buildMap, what effect, if any, would there be from rewriting `trans_map[key] = value.substr(1);` as `trans_map.insert({key, value.substr(1)})`? - use subscript operator: if a word does appear multiple times, our loops will put the **last** corresponding phrase into trans_map - use `insert`: if a word does appear multiple times, our loops will put the **first** corresponding phrase into trans_map -## Exercise 11.36: +## Exercise 11.36 + >Our program does no checking on the validity of either input file. In particular, it assumes that the rules in the transformation file are all sensible. What would happen if a line in that file has a key, one space, and then the end of the line? Predict the behavior and then check it against your version of the program. @@ -125,7 +157,8 @@ we added a file that name "word_transformation_bad.txt" to folder `data`. the fi the program of 11.33 don't influenced by that. -## Exercise 11.37: +## Exercise 11.37 + >What are the advantages of an unordered container as compared to the ordered version of that container? What are the advantages of the ordered version? - the advantages of an unordered container: diff --git a/ch12/README.md b/ch12/README.md index 47f0bda0..1d1f3f55 100644 --- a/ch12/README.md +++ b/ch12/README.md @@ -1,7 +1,9 @@ # Chapter 12. Dynamic Memory -## Exercise 12.1: +## Exercise 12.1 + >How many elements do b1 and b2 have at the end of this code? + ```cpp StrBlob b1; { @@ -19,7 +21,8 @@ so b1 and b2 both have 4 elements. [StrBlob](ex12_02.h) | [TEST](ex12_02_TEST.cpp) -## Exercise 12.3: +## Exercise 12.3 + >Does this class need const versions of push_back and pop_back? If so, add them. If not, why aren’t they needed? You can certainly do this if you want to, but there doesn't seem to be any @@ -33,7 +36,8 @@ Discussion over this exercise on [Stack Overflow](http://stackoverflow.com/quest Discussion over this exercise more on [douban](http://www.douban.com/group/topic/61573279/)(chinese) -## Exercise 12.4: +## Exercise 12.4 + >In our check function we didn’t check whether i was greater than zero. Why is it okay to omit that check? Because the type of `i` is `std::vector::size_type` which @@ -41,7 +45,8 @@ is an `unsigned`.When any argument less than 0 is passed in, it will convert to a number greater than 0. In short `std::vector::size_type` will ensure it is a positive number or 0. -## Exercise 12.5: +## Exercise 12.5 + >We did not make the constructor that takes an initializer_list explicit (7.5.4, p. 296). Discuss the pros and cons of this design choice. [@Mooophy](https://github.com/Mooophy): @@ -51,21 +56,24 @@ This design choice would easy to use but hard to debug. [@pezy](https://github.com/pezy): -**Pros** +### Pros - The compiler will not use this constructor **in an automatic conversion**. - We can realize clearly which class we have used. -**Cons** +### Cons - We always uses the constructor to construct **a temporary StrBlob object**. - cannot use the copy form of initialization with an explicit constructor. not easy to use. ## [Exercise 12.6](ex12_06.cpp) + ## [Exercise 12.7](ex12_07.cpp) -## Exercise 12.8: +## Exercise 12.8 + >Explain what if anything is wrong with the following function. + ```cpp bool b() { int* p = new int; @@ -76,8 +84,10 @@ bool b() { The p will convert to a bool ,which means that the dynamic memory allocated has no chance to be freed. As a result, memory leakage will occur. -## Exercise 12.9: +## Exercise 12.9 + >Explain what happens in the following code: + ```cpp int *q = new int(42), *r = new int(100); r = q; @@ -92,31 +102,48 @@ Memory leakage happens. Because after `r = q` was executed, no pointer points to - to `q2` and `r2`: ## [Exercise 12.10](ex12_10.cpp) + ## [Exercise 12.11](ex12_11.cpp) + ## [Exercise 12.12](ex12_12.cpp) + ## [Exercise 12.13](ex12_13.cpp) + ## [Exercise 12.14](ex12_14.cpp) + ## [Exercise 12.15](ex12_15.cpp) + ## [Exercise 12.16](ex12_16.cpp) + ## [Exercise 12.17 and 12.18](ex12_17_18.cpp) + ## Exercise 12.19 [Header](ex12_19.h)|[Implementation](ex12_19.cpp) + ## [Exercise 12.20](ex12_20.cpp) -## Exercise 12.21: + +## Exercise 12.21 + >We could have written StrBlobPtr’s deref member as follows: + ```cpp std::string& deref() const { return (*check(curr, "dereference past end"))[curr]; } ``` + Which version do you think is better and why? the origin version is better. cause it's more **readability** and **easier to debug**. ## Exercise 12.22 [Header](ex12_22.h)|[Implementation](ex12_22.cpp) + ## [Exercise 12.23](ex12_23.cpp) + ## [Exercise 12.24](ex12_24.cpp) -## Exercise 12.25: +## Exercise 12.25 + >Given the following new expression, how would you delete pa? + ```cpp int *pa = new int[10]; ``` @@ -126,11 +153,13 @@ delete [] pa; ``` ## [Exercise 12.26](ex12_26.cpp) + ## Exercise 12.27 [Header](ex12_27_30.h)|[Implementation](ex12_27_30.cpp)|[Test](ex12_27_30_TEST.cpp) ## [Exercise 12.28](ex12_28.cpp) -## Exercise 12.29: +## Exercise 12.29 + >We could have written the loop to manage the interaction with the user as a do while (5.4.4, p. 189) loop. Rewrite the loop to use a do while. Explain which version you prefer and why. ```cpp @@ -146,10 +175,12 @@ I prefer the `do while`, cause the process according with our logic. ## Exercise 12.30 [Header](ex12_27_30.h)|[Implementation](ex12_27_30.cpp)|[Test](ex12_27_30_TEST.cpp) -## Exercise 12.31: +## Exercise 12.31 + >What difference(s) would it make if we used a vector instead of a set to hold the line numbers? Which approach is better? Why? The `vector` can not ensure no duplicates. Hence, in terms of this programme `set` is a better option. ## Exercise 12.32 [Header](ex12_32.h)|[Implementation](ex12_32.cpp) + ## Exercise 12.33 [Header](ex12_33.h)|[Implementation](ex12_33.cpp) diff --git a/ch13/README.md b/ch13/README.md index 1da72d8b..4e048648 100644 --- a/ch13/README.md +++ b/ch13/README.md @@ -1,7 +1,6 @@ # Chapter 13. Copy Control -Exercise 13.1: --------------- +## Exercise 13.1 > What is a copy constructor? When is it used? @@ -9,14 +8,13 @@ A copy constructor is a constructor which first parameter is a **reference** to When copy initialization happens and that copy initialization requires either the copy constructor or the move constructor. -- Define variables using an `=` -- Pass an object as an argument to a parameter of non-reference type -- Return an object from a function that has a non-reference return type -- Brace initialize the elements in an array or the members of an aggregate class -- Some class types also use copy initialization for the objects they allocate. +- Define variables using an `=` +- Pass an object as an argument to a parameter of non-reference type +- Return an object from a function that has a non-reference return type +- Brace initialize the elements in an array or the members of an aggregate class +- Some class types also use copy initialization for the objects they allocate. -Exercise 13.2: --------------- +## Exercise 13.2 > Explain why the following declaration is illegal: > @@ -26,8 +24,7 @@ Exercise 13.2: If declaration like that, the call would never succeed to call the copy constructor, `Sales_data rhs` is an argument to a parameter, thus, we'd need to use the copy constructor to copy the argument, but to copy the argument, we'd need to call the copy constructor, and so on indefinitely. -Exercise 13.3: --------------- +## Exercise 13.3 > What happens when we copy a `StrBlob`? What about `StrBlobPtrs`? @@ -53,8 +50,7 @@ when we copy a `StrBlob`, the `shared_ptr` member's use_count add one. when we copy a `StrBlobPrts`, the `weak_ptr` member's use_count isn't changed.(cause the count belongs to `shared_ptr`\) -Exercise 13.4: --------------- +## Exercise 13.4 > Assuming Point is a class type with a public copy constructor, identify each use of the copy constructor in this program fragment: > @@ -69,11 +65,9 @@ Exercise 13.4: > } > ``` -[Exercise 13.5](ex13_05.h) --------------------------- +## [Exercise 13.5](ex13_05.h) -Exercise 13.6: --------------- +## Exercise 13.6 > What is a `copy-assignment` operator? When is this operator used? What does the synthesized `copy-assignment` operator do? When is it synthesized? @@ -85,18 +79,15 @@ The synthesized `copy-assignment` operator assigns each non-static member of the It is synthesized when the class does not define its own. -Exercise 13.7: --------------- +## Exercise 13.7 > What happens when we assign one `StrBlob` to another? What about `StrBlobPtrs`? In both cases, shallow copy will happen. All pointers point to the same address. The `use_count` changed the same as 13.3. -[Exercise 13.8](ex13_08.h) --------------------------- +## [Exercise 13.8](ex13_08.h) -Exercise 13.9: --------------- +## Exercise 13.9 > What is a destructor? What does the synthesized destructor do? When is a destructor synthesized? @@ -106,8 +97,7 @@ As with the copy constructor and the copy-assignment operator, for some classes, The compiler defines a synthesized destructor for any class that does not define its own destructor. -Exercise 13.10: ---------------- +## Exercise 13.10 > What happens when a `StrBlob` object is destroyed? What about a `StrBlobPtr`? @@ -115,11 +105,9 @@ When a `StrBlob` object destroyed, the `use_count` of the dynamic object will de When a `StrBlobPter` object is destroyed the object dynamically allocated will not be freed. -[Exercise 13.11](ex13_11.h) ---------------------------- +## [Exercise 13.11](ex13_11.h) -Exercise 13.12: ---------------- +## Exercise 13.12 > How many destructor calls occur in the following code fragment? > @@ -133,11 +121,9 @@ Exercise 13.12: 3 times. There are `accum`, `item1` and `item2`. -[Exercise 13.13](ex13_13.cpp) ------------------------------ +## [Exercise 13.13](ex13_13.cpp) -Exercise 13.14: ---------------- +## Exercise 13.14 > Assume that `numbered` is a class with a default constructor that generates a unique serial number for each object, which is stored in a data member named `mysn`. Assuming numbered uses the synthesized copy-control members and given the following function: > @@ -154,66 +140,55 @@ Exercise 13.14: Three identical numbers. -Exercise 13.15: ---------------- +## Exercise 13.15 -> Assume `numbered` has a copy constructor that generates a new serial number. Does that change the output of the calls in the previous exercise? If so, why? What output gets generated? +> Assume `numbered` has a copy constructor that generates a new serial number. Does that change the output of the calls in the previous Exercise? If so, why? What output gets generated? Yes, the output will be changed. cause we don't use the synthesized copy-control members rather than own defined.The output will be three different numbers. -Exercise 13.16: ---------------- +## Exercise 13.16 > What if the parameter in `f` were `const numbered&`? Does that change the output? If so, why? What output gets generated? Yes, the output will be changed. cause the function `f` haven't any copy operators. Thus, the output are the same when pass the each object to `f`. -Exercise 13.17 --------------- +## Exercise 13.17 > Write versions of `numbered` and `f` corresponding to the previous three exercises and check whether you correctly predicted the output. [13.14](ex13_17_1.cpp) | [13.15](ex13_17_2.cpp) | [13.16](ex13_17_3.cpp) -Exercise 13.18 [hpp](ex13_18.h) | [cpp](ex13_18.cpp) ----------------------------------------------------- +## Exercise 13.18 [hpp](ex13_18.h) | [cpp](ex13_18.cpp) -[Exercise 13.19](ex13_19.h) ---------------------------- +## [Exercise 13.19](ex13_19.h) -Exercise 13.20: ---------------- +## Exercise 13.20 > Explain what happens when we copy, assign, or destroy objects of our `TextQuery` and `QueryResult` classes from 12.3 (p. 484). The member (smart pointer and container) will be copied. -Exercise 13.21: ---------------- +## Exercise 13.21 > Do you think the `TextQuery` and `QueryResult` classes need to define their own versions of the copy-control members? If so, why? If not, why not? Implement whichever copy-control operations you think these classes require. As synthesized version meet all requirements for this case, no custom version control members need to define. Check [#304](https://github.com/Mooophy/Cpp-Primer/issues/304#issuecomment-124081395) for detail. -[Exercise 13.22](ex13_22.h) ---------------------------- +## [Exercise 13.22](ex13_22.h) -Exercise 13.23: ---------------- +## Exercise 13.23 > Compare the copy-control members that you wrote for the solutions to the previous section’s exercises to the code presented here. Be sure you understand the differences, if any, between your code and ours. Check 13.22. -Exercise 13.24: ---------------- +## Exercise 13.24 > What would happen if the version of `HasPtr` in this section didn’t define a destructor? What if `HasPtr` didn’t define the copy constructor? If `HasPtr` didn't define a destructor, memory leak will happened. If `HasPtr` didn't define the copy constructor, when assignment happened, just points copied, the string witch `ps` points haven't been copied. -Exercise 13.25: ---------------- +## Exercise 13.25 > Assume we want to define a version of `StrBlob` that acts like a value. Also assume that we want to continue to use a shared_ptr so that our `StrBlobPtr` class can still use a weak_ptr to the vector. Your revised class will need a copy constructor and copy-assignment operator but will not need a destructor. Explain what the copy constructor and copy-assignment operators must do. Explain why the class does not need a destructor. @@ -221,30 +196,23 @@ Copy constructor and copy-assignment operator should dynamically allocate memory `StrBlob` is using smart pointers which can be managed with synthesized destructor, If an object of `StrBlob` is out of scope, the destructor for std::shared_ptr will be called automatically to free the memory dynamically allocated when the `use_count` goes to 0. -Exercise 13.26 [hpp](ex13_26.h) | [cpp](ex13_26.cpp) ----------------------------------------------------- +## Exercise 13.26 [hpp](ex13_26.h) | [cpp](ex13_26.cpp) -[Exercise 13.27](ex13_27.h) ---------------------------- +## [Exercise 13.27](ex13_27.h) -Exercise 13.28 [hpp](ex13_28.h) | [cpp](ex13_28.cpp) ----------------------------------------------------- +## Exercise 13.28 [hpp](ex13_28.h) | [cpp](ex13_28.cpp) -Exercise 13.29: ---------------- +## Exercise 13.29 > Explain why the calls to swap inside swap(HasPtr&, HasPtr&) do not cause a recursion loop. `swap(lhs.ps, rhs.ps);` feed the version : `swap(std::string*, std::string*)` and `swap(lhs.i, rhs.i);` feed the version : `swap(int, int)`. Both them can't call `swap(HasPtr&, HasPtr&)`. Thus, the calls don't cause a recursion loop. -[Exercise 13.30](ex13_30.h) ---------------------------- +## [Exercise 13.30](ex13_30.h) -[Exercise 13.31](ex13_31.h) ---------------------------- +## [Exercise 13.31](ex13_31.h) -Exercise 13.32: ---------------- +## xercise 13.32 > Would the pointer-like version of `HasPtr` benefit from defining a swap function? If so, what is the benefit? If not, why not? @@ -252,31 +220,25 @@ Exercise 13.32: Essentially, the specific avoiding memory allocation is the reason why it improve performance. As for the pointer-like version, no dynamic memory allocation anyway. Thus, a specific version for it will not improve the performance. -Exercise 13.33: ---------------- +## Exercise 13.33 > Why is the parameter to the `save` and `remove` members of Message a Folder&? Why didn’t we define that parameter as `Folder`? Or `const Folder&`? Because these operations must also update the given `Folder`. Updating a `Folder` is a job that the `Folder` class controls through its `addMsg` and `remMsg` members, which will add or remove a pointer to a given `Message`, respectively. -Exercise 13.34 [hpp](ex13_34_36_37.h) | [cpp](ex13_34_36_37.cpp) | [test](ex13_34_36_37_TEST.cpp) -------------------------------------------------------------------------------------------------- +## Exercise 13.34 [hpp](ex13_34_36_37.h) | [cpp](ex13_34_36_37.cpp) | [test](ex13_34_36_37_TEST.cpp) -Exercise 13.35: ---------------- +## Exercise 13.35 > What would happen if `Message` used the synthesized versions of the copy-control members? some existing `Folders` will out of sync with the `Message` after assignment. -Exercise 13.36 [hpp](ex13_34_36_37.h) | [cpp](ex13_34_36_37.cpp) | [test](ex13_34_36_37_TEST.cpp) -------------------------------------------------------------------------------------------------- +## Exercise 13.36 [hpp](ex13_34_36_37.h) | [cpp](ex13_34_36_37.cpp) | [test](ex13_34_36_37_TEST.cpp) -Exercise 13.37 [hpp](ex13_34_36_37.h) | [cpp](ex13_34_36_37.cpp) | [test](ex13_34_36_37_TEST.cpp) -------------------------------------------------------------------------------------------------- +## Exercise 13.37 [hpp](ex13_34_36_37.h) | [cpp](ex13_34_36_37.cpp) | [test](ex13_34_36_37_TEST.cpp) -Exercise 13.38: ---------------- +## Exercise 13.38 > We did not use copy and swap to define the Message assignment operator. Why do you suppose this is so? @@ -284,18 +246,15 @@ Exercise 13.38: @pezy In this case, `swap` function is special. It will be clear two `Message`'s folders , then swap members, and added themselves to each folders. But, `Message` assignment operator just clear itself, and copy the members, and added itself to each folders. The `rhs` don't need to clear and add to folders. So, if using copy and swap to define, it will be very inefficiency. -Exercise 13.39 [hpp](ex13_39.h) | [cpp](ex13_39.cpp) ----------------------------------------------------- +## Exercise 13.39 [hpp](ex13_39.h) | [cpp](ex13_39.cpp) -Exercise 13.40 [hpp](ex13_40.h) | [cpp](ex13_40.cpp) ----------------------------------------------------- +## Exercise 13.40 [hpp](ex13_40.h) | [cpp](ex13_40.cpp) -Exercise 13.41: ---------------- +## Exercise 13.41 > Why did we use postfix increment in the call to construct inside push_back? What would happen if it used the prefix increment? -``` +```sh |a|b|c|d|f|..............| ^ ^ ^ elements first_free cap @@ -313,21 +272,19 @@ elements | first_free cap "unconstructed" ``` -Exercise 13.42: ---------------- +## Exercise 13.42 > Test your `StrVec` class by using it in place of the `vector` in your `TextQuery` and `QueryResult` classes (12.3, p. 484). -- StrVec : [hpp](ex13_42_StrVec.h) | [cpp](ex13_42_StrVec.cpp) -- TextQuery and QueryResult : [hpp](ex13_42_TextQuery.h) | [cpp](ex13_42_TextQuery.cpp) -- Text : [ex13_42.cpp](ex13_42.cpp) +- StrVec : [hpp](ex13_42_StrVec.h) | [cpp](ex13_42_StrVec.cpp) +- TextQuery and QueryResult : [hpp](ex13_42_TextQuery.h) | [cpp](ex13_42_TextQuery.cpp) +- Text : [ex13_42.cpp](ex13_42.cpp) -Exercise 13.43: ---------------- +## Exercise 13.43 > Rewrite the free member to use `for_each` and a lambda (10.3.2, p. 388) in place of the for loop to destroy the elements. Which implementation do you prefer, and why? -**Rewrite** +### Rewrite ```cpp for_each(elements, first_free, [this](std::string &rhs){ alloc.destroy(&rhs); }); @@ -335,8 +292,7 @@ for_each(elements, first_free, [this](std::string &rhs){ alloc.destroy(&rhs); }) @Mooophy: The new version is better. Compared to the old one, it doesn't need to worry about the order and decrement.So more straightforward and handy. The only thing to do for using this approach is to add "&" to build the pointers to string pointers. -Exercise 13.44: ---------------- +## Exercise 13.44 > Write a class named String that is a simplified version of the library string class. Your class should have at least a default constructor and a constructor that takes a pointer to a C-style string. Use an allocator to allocate memory that your String class uses. @@ -344,15 +300,14 @@ Exercise 13.44: more information to see [A trivial String class that designed for write-on-paper in an interview](https://github.com/chenshuo/recipes/blob/fcf9486f5155117fb8c36b6b0944c5486c71c421/string/StringTrivial.h) -Exercise 13.45: ---------------- +## Exercise 13.45 > Distinguish between an `rvalue` reference and an `lvalue` reference. Definition: -- `lvalue` reference: reference that can bind to **an lvalue**. (Regular reference) -- `rvalue` reference: reference **to an object that is about to be destroyed**. +- `lvalue` reference: reference that can bind to **an lvalue**. (Regular reference) +- `rvalue` reference: reference **to an object that is about to be destroyed**. We can bind an `rvalue` reference to expression that require conversion, to literals, or to expressions that return an `rvalue`, but we cannot directly bind an `rvalue` reference to an `lvalue`. @@ -365,11 +320,10 @@ const int &r3 = i*42; // reference to const (bind to a rvalue) int &&rr2 = i*42; // rvalue reference ``` -- `lvalue` : functions that return lvalue references, assignment, subscript, dereference, and prefix increment/decrement operator. -- `rvalue const` reference : functions that return a non-references, arithmetic, relational bitwise, postfix increment/decrement operators. +- `lvalue` : functions that return lvalue references, assignment, subscript, dereference, and prefix increment/decrement operator. +- `rvalue const` reference : functions that return a non-references, arithmetic, relational bitwise, postfix increment/decrement operators. -Exercise 13.46: ---------------- +## Exercise 13.46 > Which kind of reference can be bound to the following initializers? > @@ -382,23 +336,19 @@ Exercise 13.46: > int&& r4 = vi[0] * f(); > ``` -Exercise 13.47 [hpp](ex13_44_47.h) | [cpp](ex13_44_47.cpp) ----------------------------------------------------------- +## Exercise 13.47 [hpp](ex13_44_47.h) | [cpp](ex13_44_47.cpp) -[Exercise 13.48](ex13_48.cpp) ------------------------------ +## [Exercise 13.48](ex13_48.cpp) -Exercise 13.49: ---------------- +## Exercise 13.49 > Add a move constructor and move-assignment operator to your `StrVec`, `String`, and `Message` classes. -- StrVec: [hpp](ex13_49_StrVec.h) | [cpp](ex13_49_StrVec.cpp) -- String: [hpp](ex13_49_String.h) | [cpp](ex13_49_String.cpp) -- Message:[hpp](ex13_49_Message.h) | [cpp](ex13_49_Message.cpp) | [test](ex13_49_Message_TEST.cpp) +- StrVec: [hpp](ex13_49_StrVec.h) | [cpp](ex13_49_StrVec.cpp) +- String: [hpp](ex13_49_String.h) | [cpp](ex13_49_String.cpp) +- Message:[hpp](ex13_49_Message.h) | [cpp](ex13_49_Message.cpp) | [test](ex13_49_Message_TEST.cpp) -Exercise 13.50: ---------------- +## Exercise 13.50 > Put print statements in the move operations in your String class and rerun the program from exercise 13.48 in 13.6.1 (p. 534) that used a `vector` to see when the copies are avoided. @@ -412,8 +362,7 @@ String baz() String s5 = baz(); // second avoided ``` -Exercise 13.51: ---------------- +## Exercise 13.51 > Although `unique_ptrs` cannot be copied, in 12.1.5 (p. 471) we wrote a clone function that returned a `unique_ptr` by value. Explain why that function is legal and how it works. @@ -428,8 +377,7 @@ unique_ptr clone(int p) { the result of a call to `clone` is an **rvalue**, so it uses the move-assignment operator rather than copy-assignment operator. Thus, it is legal and can pretty work. -Exercise 13.52: ---------------- +## Exercise 13.52 > Explain in detail what happens in the assignments of the `HasPtr` objects on page 541. In particular, describe step by step what happens to values of `hp`, `hp2`, and of the `rhs` parameter in the `HasPtr` assignment operator. @@ -439,8 +387,7 @@ Exercise 13.52: Thus, in `hp = hp2;`, `hp2` is an `lvalue`, copy constructor used to copy `hp2`. In `hp = std::move(hp2);`, move constructor moves `hp2`. -Exercise 13.53: ---------------- +## Exercise 13.53 > As a matter of low-level efficiency, the `HasPtr` assignment operator is not ideal. Explain why. Implement a copy-assignment and move-assignment operator for `HasPtr` and compare the operations executed in your new move-assignment operator versus the copy-and-swap version. @@ -450,19 +397,17 @@ nothing to say, just see the versus codes: see more information at [this question && answer](http://stackoverflow.com/questions/21010371/why-is-it-not-efficient-to-use-a-single-assignment-operator-handling-both-copy-a). -Exercise 13.54: ---------------- +## Exercise 13.54 > What would happen if we defined a `HasPtr` move-assignment operator but did not change the copy-and-swap operator? Write code to test your answer. -``` +```sh error: ambiguous overload for 'operator=' (operand types are 'HasPtr' and 'std::remove_reference::type {aka HasPtr}') hp1 = std::move(*pH); ^ ``` -Exercise 13.55: ---------------- +## Exercise 13.55 > Add an `rvalue` reference version of `push_back` to your `StrBlob`. @@ -470,8 +415,7 @@ Exercise 13.55: void push_back(string &&s) { data->push_back(std::move(s)); } ``` -Exercise 13.56: ---------------- +## Exercise 13.56 > What would happen if we defined sorted as: > @@ -486,8 +430,7 @@ recursion and stack overflow. @miaojiuchen: Because the local variable `ret` here is an `lvalue`, so when we call `ret.sorted()`, we are actually not calling the member function `Foo Foo::sorted() &&` as expected, but `Foo Foo::sorted() const &` instead. As a result, the code will be trapped into a recursion and causes a deadly stack overflow. -Exercise 13.57: ---------------- +## Exercise 13.57 > What if we defined sorted as: > @@ -497,9 +440,4 @@ Exercise 13.57: OK, it will call the move version. -Exercise 13.58: ---------------- - -> Write versions of class `Foo` with print statements in their sorted functions to test your answers to the previous two exercises. - -[Exercise 13.58](ex13_58.cpp) +## [Exercise 13.58](ex13_58.cpp) diff --git a/ch13/ex13_58.cpp b/ch13/ex13_58.cpp index 7d4f7be8..f1852a2d 100644 --- a/ch13/ex13_58.cpp +++ b/ch13/ex13_58.cpp @@ -1,3 +1,5 @@ +// Write versions of class `Foo` with print statements in their sorted functions to test your answers to the previous two exercises. + #include #include #include diff --git a/ch14/README.md b/ch14/README.md index 6080e299..bc35a397 100644 --- a/ch14/README.md +++ b/ch14/README.md @@ -1,25 +1,29 @@ # Chapter 14. Overloaded Operations and Conversions -## Exercise 14.1: +## Exercise 14.1 + >In what ways does an overloaded operator differ from a built-in operator? In what ways are overloaded operators the same as the built-in operators? -**Differ** -1. We can call an overloaded operator function directly. -2. An overloaded operator function must either be a member of a class or have at least one parameter of class type. -3. A few operators guarantee the order in which operands are evaluated. These overloaded versions of these operators do not preserve order of evaluation and/or short-circuit evaluation, it is usually a bad idea to overload them. +Differ: + +- We can call an overloaded operator function directly. +- An overloaded operator function must either be a member of a class or have at least one parameter of class type. +- A few operators guarantee the order in which operands are evaluated. These overloaded versions of these operators do not preserve order of evaluation and/or short-circuit evaluation, it is usually a bad idea to overload them. > In particular, the operand-evaluation guarantees of the logical `AND`, logical `OR`, and comma operators are not preserved, Moreover, overloaded versions of `&&` or `||` operators do not preserve short-circuit evaluation properties of the built-in operators. Both operands are always evaluated. -**Same** +Same: - An overloaded operator has the same precedence and associativity as the corresponding built-in operator. -## Exercise 14.2: +## Exercise 14.2 + >Write declarations for the overloaded input, output, addition, and compound-assignment operators for `Sales_data`. [hpp](ex14_02.h) | [cpp](ex14_02.cpp) -## Exercise 14.3: ->Both `string` and `vector` define an overloaded == that can be used to compare objects of those types. Assuming `svec1` and `svec2 `are `vectors` that hold `strings`, identify which version of == is applied in each of the following expressions: +## Exercise 14.3 + +> Both `string` and `vector` define an overloaded == that can be used to compare objects of those types. Assuming `svec1` and `svec2 `are `vectors` that hold `strings`, identify which version of == is applied in each of the following expressions: - (a) `"cobble" == "stone"` - (b) `svec1[0] == svec2[0]` - (c) `svec1 == svec2` @@ -29,11 +33,14 @@ ----- -**Reference** +Reference: + - [Why does the following not invoke the overloaded operator== (const String &, const String &)? “cobble” == “stone”](http://stackoverflow.com/questions/2690737/why-does-the-following-not-invoke-the-overloaded-operator-const-string-con) -## Exercise 14.4: ->Explain how to decide whether the following should be class members: +## Exercise 14.4 + +> Explain how to decide whether the following should be class members: + - (a) % - (b) %= - (c) ++ @@ -59,46 +66,56 @@ (h) = () [] -> must be member -## Exercise 14.5: +## Exercise 14.5 + >In exercise 7.40 from 7.5.1 (p. 291) you wrote a sketch of one of the following classes. Decide what, if any, overloaded operators your class should provide. Such as `Book` [hpp](ex14_05.h) | [cpp](ex14_05.cpp) | [test](ex14_05_TEST.cpp) -## Exercise 14.6: +## Exercise 14.6 + >Define an output operator for your `Sales_data` class. see [Exercise 14.2](#exercise-142). -## Exercise 14.7: +## Exercise 14.7 + >Define an output operator for you `String` class you wrote for the exercises in 13.5 (p. 531). [hpp](ex14_07.h) | [cpp](ex14_07.cpp) | [Test](ex14_07_TEST.cpp) -## Exercise 14.8: +## Exercise 14.8 + >Define an output operator for the class you chose in exercise 7.40 from 7.5.1 (p. 291). see [Exercise 14.5](#exercise-145) -## Exercise 14.9: +## Exercise 14.9 + >Define an input operator for your Sales_data class. see [Exercise 14.2](#exercise-142). -## Exercise 14.10: +## Exercise 14.10 + >Describe the behaviour of the Sales_data input operator if given the following input: + - (a) 0-201-99999-9 10 24.95 - (b) 10 24.95 0-210-99999-9 - (a) correct format. - (b) ilegal input. But `0-210-99999-9` will be converted to a float stored in this object. As a result, the data inside will be a wrong one. + Output: `10 24 22.8 0.95` check [Test](ex14_02_TEST.cpp) -## Exercise 14.11: +## Exercise 14.11 + >What, if anything, is wrong with the following Sales_data input operator? What would happen if we gave this operator the data in the previous exercise? + ```cpp istream& operator>>(istream& in, Sales_data& s) { @@ -111,56 +128,66 @@ istream& operator>>(istream& in, Sales_data& s) no input check. nothing happend. -## Exercise 14.12: +## Exercise 14.12 + >Define an input operator for the class you used in exercise 7.40 from 7.5.1 (p. 291). Be sure the operator handles input errors. see [Exercise 14.5](#exercise-145) -## Exercise 14.13: +## Exercise 14.13 + >Which other arithmetic operators (Table 4.1 (p. 139)), if any, do you think Sales_data ought to support? Define any you think the class should include. no others. -## Exercise 14.14: +## Exercise 14.14 + >Why do you think it is more efficient to define `operator+` to call `operator+=` rather than the other way around? Discussing on [SO](http://stackoverflow.com/questions/21071167/why-is-it-more-efficient-to-define-operator-to-call-operator-rather-than-the). -## Exercise 14.15: +## Exercise 14.15 + >Should the class you chose for exercise 7.40 from 7.5.1 (p. 291) define any of the arithmetic operators? If so, implement them. If not, explain why not. [hpp](ex14_15.h) | [cpp](ex14_15.cpp) | [Test](ex14_15_TEST.cpp) -## Exercise 14.16: +## Exercise 14.16 + >Define equality and inequality operators for your `StrBlob` (12.1.1, p. 456), `StrBlobPtr` (12.1.6, p. 474), `StrVec` (13.5, p.526), and `String` (13.5, p. 531) classes. - `StrBlob` & `StrBlobPtr`: [hpp](ex14_16_StrBlob.h) | [cpp](ex14_16_StrBlob.cpp) | [Test](ex14_16_StrBlobTest.cpp) - `StrVec`: [hpp](ex14_16_StrVec.h) | [cpp](ex14_16_StrVec.cpp) | [Test](ex14_16_StrVecMain.cpp) - `String`: [hpp](ex14_16_String.h) | [cpp](ex14_16_String.cpp) | [Test](ex14_16_StringMain.cpp) -## Exercise 14.17: +## Exercise 14.17 + >Should the class you chose for exercise 7.40 from 7.5.1(p. 291) define the equality operators? If so, implement them. If not, explain why not. yes.see [Exercise 14.15](#exercise-1415) -## Exercise 14.18: +## Exercise 14.18 + >Define relational operators for your `StrBlob`, `StrBlobPtr`, `StrVec`, and `String` classes. - `StrBlob` & `StrBlobPtr`: [hpp](ex14_18_StrBlob.h) | [cpp](ex14_18_StrBlob.cpp) | [Test](ex14_18_StrBlobTest.cpp) - `StrVec`: [hpp](ex14_18_StrVec.h) | [cpp](ex14_18_StrVec.cpp) | [Test](ex14_18_StrVecMain.cpp) - `String`: [hpp](ex14_18_String.h) | [cpp](ex14_18_String.cpp) | [Test](ex14_18_StringMain.cpp) -## Exercise 14.19: +## Exercise 14.19 + >Should the class you chose for exercise 7.40 from 7.5.1 (p. 291) define the relational operators? If so, implement them. If not, explain why not. yes.see [Exercise 14.15](#exercise-1415) -## Exercise 14.20: +## Exercise 14.20 + >Define the addition and compound-assignment operators for your `Sales_data` class. see [Exercise 14.2](#exercise-142). -## Exercise 14.21: +## Exercise 14.21 + >Write the `Sales_data` operators so that `+` does the actual addition and `+=` calls `+`. Discuss the disadvantages of this approach compared to the way these operators were defined in 14.3 (p. 560) and 14.4 (p.564). ```cpp @@ -182,71 +209,84 @@ Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs) **Disadvantages**: Both `+` and `+=`, uses an temporary object of `Sales_data`. But it is no need for that. -## Exercise 14.22: +## Exercise 14.22 + >Define a version of the assignment operator that can assign a `string` representing an ISBN to a `Sales_data`. [hpp](ex14_22.h) | [cpp](ex14_22.cpp) | [Test](ex14_22_TEST.cpp) -## Exercise 14.23: +## Exercise 14.23 + >Define an initializer_list assignment operator for your version of the `StrVec` class. [hpp](ex14_23.h) | [cpp](ex14_23.cpp) | [Test](ex14_23_TEST.cpp) -## Exercise 14.24: +## Exercise 14.24 + >Decide whether the class you used in exercise 7.40 from 7.5.1 (p. 291) needs a copy- and move-assignment operator. If so, define those operators. [hpp](ex14_24.h) | [cpp](ex14_24.cpp) | [Test](ex14_24_TEST.cpp) -## Exercise 14.25: +## Exercise 14.25 + >Implement any other assignment operators your class should define. Explain which types should be used as operands and why. see [Exercise 14.24](#exercise-1424) -## Exercise 14.26: +## Exercise 14.26 + >Define subscript operators for your `StrVec`, `String`, `StrBlob`, and `StrBlobPtr` classes. - `StrBlob` & `StrBlobPtr`: [hpp](ex14_26_StrBlob.h) | [cpp](ex14_26_StrBlob.cpp) | [Test](ex14_26_StrBlobTest.cpp) - `StrVec`: [hpp](ex14_26_StrVec.h) | [cpp](ex14_26_StrVec.cpp) | [Test](ex14_26_StrVecMain.cpp) - `String`: [hpp](ex14_26_String.h) | [cpp](ex14_26_String.cpp) | [Test](ex14_26_StringMain.cpp) -## Exercise 14.27: +## Exercise 14.27 + > Add increment and decrement operators to your `StrBlobPtr` class. [hpp](ex14_27_28_StrBlob.h) | [cpp](ex14_27_28_StrBlob.cpp) | [Test](ex14_27_28_StrBlobTest.cpp) -## Exercise 14.28: +## Exercise 14.28 + > Define addition and subtraction for `StrBlobPtr` so that these operators implement pointer arithmetic (3.5.3, p. 119). see [Exercise 14.27](#exercise-1427) -## Exercise 14.29: +## Exercise 14.29 + > We did not define a `const` version of the increment and decrement operators. Why not? Because `++` and `--` change the state of the object. Hence ,it's meaningless to do so. -## Exercise 14.30: +## Exercise 14.30 + > Add dereference and arrow operators to your `StrBlobPtr` class and to the `ConstStrBlobPtr` class that you defined in exercise 12.22 from 12.1.6 (p. 476). Note that the operators in `constStrBlobPtr` must return `const` references because the `data` member in `constStrBlobPtr` points to a `const vector`. [hpp](ex14_30_StrBlob.h) | [cpp](ex14_30_StrBlob.cpp) | [Test](ex14_30_StrBlobTest.cpp) -## Exercise 14.31: +## Exercise 14.31 + > Our StrBlobPtr class does not define the copy constructor, assignment operator, or a destructor. Why is that okay? Applying the Rule of 3/5: There is no dynamic allocation to deal with, so the synthesized destructor is enough. Moreover, no unique is needed. Hence, the synthesized ones can handle all the corresponding operations. -## Exercise 14.32: +## Exercise 14.32 + > Define a class that holds a pointer to a `StrBlobPtr`. Define the overloaded arrow operator for that class. [hpp](ex14_32.h) | [cpp](ex14_32.cpp) -## Exercise 14.33: +## Exercise 14.33 + > How many operands may an overloaded function-call operator take? An overloaded operator function has the same number of parameters as the operator has operands. Hence the maximum value should be around 256. ([question on SO](http://stackoverflow.com/questions/21211889/how-many-operands-may-an-overloaded-function-call-operator-take)) -## Exercise 14.34: +## Exercise 14.34 + > Define a function-object class to perform an if-then-else operation: The call operator for this class should take three parameters. It should test its first parameter and if that test succeeds, it should return its second parameter; otherwise, it should return its third parameter. ```cpp @@ -257,42 +297,50 @@ struct Test { }; ``` -## Exercise 14.35: +## Exercise 14.35 + > Write a class like `PrintString` that reads a line of input from an `istream` and returns a `string` representing what was read. If the read fails, return the empty `string`. [Test](ex14_35.cpp) -## Exercise 14.36: +## Exercise 14.36 + > Use the class from the previous exercise to read the standard input, storing each line as an element in a vector. [Test](ex14_36.cpp) -## Exercise 14.37: +## Exercise 14.37 + > Write a class that tests whether two values are equal. Use that object and the library algorithms to write a program to replace all instances of a given value in a sequence. [Test](ex14_37.cpp) -## Exercise 14.38: +## Exercise 14.38 + > Write a class that tests whether the length of a given `string` matches a given bound. Use that object to write a program to report how many words in an input file are of sizes 1 through 10 inclusive. [BoundTest](ex14_38_39.cpp) -## Exercise 14.39: +## Exercise 14.39 + > Revise the previous program to report the count of words that are sizes 1 through 9 and 10 or more. see [Exercise 14.38](#exercise-1438) -## Exercise 14.40: +## Exercise 14.40 + > Rewrite the `biggies` function from 10.3.2 (p. 391) to use function-object classes in place of lambdas. [Test](ex14_40.cpp) -## Exercise 14.41: +## Exercise 14.41 + > Why do you suppose the new standard added lambdas? Explain when you would use a lambda and when you would write a class instead. IMO, lambda is quite handy to use. Lambda can be used when the functor is not used frequently nor complicated, whereas functor is supposed to call more times than lambda or quite complicated to implement as a lambda. -## Exercise 14.42: +## Exercise 14.42 + > Using library function objects and adaptors, define an expression to - (a) Count the number of values that are greater than 1024 - (b) Find the first string that is not equal to `pooh` @@ -306,28 +354,34 @@ std::transform(ivec.begin(), ivec.end(), ivec.begin(), std::bind(std::multiplies [Test](ex14_42.cpp) -## Exercise 14.43: +## Exercise 14.43 + > Using library function objects, determine whether a given `int` value is divisible by any element in a container of `int`s. [ex14_43.cpp](ex14_43.cpp) -## Exercise 14.44: +## Exercise 14.44 + > Write your own version of a simple desk calculator that can handle binary operations. [ex14_44.cpp](ex14_44.cpp) -## Exercise 14.45: +## Exercise 14.45 + > Write conversion operators to convert a `Sales_data` to `string` and to `double`. What values do you think these operators should return? [hpp](ex14_45.h) | [cpp](ex14_45.cpp) | [Test](ex14_45_TEST.cpp) -## Exercise 14.46: +## Exercise 14.46 + > Explain whether defining these Sales_data conversion operators is a good idea and whether they should be explicit. It's a bad idea to do so, because these conversion is misleading.`explicit` should be added to prevent implicit conversion. -## Exercise 14.47: +## Exercise 14.47 + > Explain the difference between these two conversion operators: + ```cpp struct Integral { operator const int(); // meaningless, it will be ignored by compiler. @@ -335,18 +389,22 @@ struct Integral { }; ``` -## Exercise 14.48: +## Exercise 14.48 + > Determine whether the class you used in exercise 7.40 from 7.5.1 (p. 291) should have a conversion to `bool`. If so, explain why, and explain whether the operator should be `explicit`. If not, explain why not. A conversion to bool can be useful for the class Date. But it must be an explicit one to prevent any automatic conversion. -## Exercise 14.49: +## Exercise 14.49 + > Regardless of whether it is a good idea to do so, define a conversion to bool for the class from the previous exercise. [hpp](ex14_49.h) | [cpp](ex14_49.cpp) | [Test](ex14_49_TEST.cpp) -## Exercise 14.50: +## Exercise 14.50 + > Show the possible class-type conversion sequences for the initializations of ex1 and ex2. Explain whether the initializations are legal or not. + ```cpp struct LongDouble { LongDouble(double = 0.0); @@ -358,8 +416,10 @@ int ex1 = ldObj; // error ambiguous: double or float? float ex2 = ldObj; // legal ``` -## Exercise 14.51: +## Exercise 14.51 + > Show the conversion sequences (if any) needed to call each version of `calc` and explain why the best viable function is selected. + ```cpp void calc(int); void calc(LongDouble); @@ -372,13 +432,15 @@ best viable function: `void calc(int)`. cause class-type conversion is the lowes review the order: 1. exact match -2. const conversion -3. promotion -4. arithmetic or pointer conversion -5. class-type conversion +1. const conversion +1. promotion +1. arithmetic or pointer conversion +1. class-type conversion + +## Exercise 14.52 + +> Which `operator+`, if any, is selected for each of the addition expressions? List the candidate functions, the viable functions, and the type conversions on the arguments for each viable function -## Exercise 14.52: -> Which `operator+`, if any, is selected for each of the addition expressions? List the candidate functions, the viable functions, and the type conversions on the arguments for each viable function: ```cpp struct LongDouble { // member operator+ for illustration purposes; + is usually a nonmember LongDouble operator+(const SmallInt&); // 1 @@ -393,9 +455,10 @@ ld = ld + si; `ld = si + ld;` is ambiguous. `ld = ld + si` can use both 1 and 2, but 1 is more exactly. (in the 2, SmallInt need to convert to `double`) +## Exercise 14.53 -## Exercise 14.53: > Given the definition of SmallInt on page 588, determine whether the following addition expression is legal. If so, what addition operator is used? If not, how might you change the code to make it legal? + ```cpp SmallInt s1; double d = s1 + 3.14; @@ -403,7 +466,8 @@ double d = s1 + 3.14; ambiguous. -**Fixed**: +Fixed: + ```cpp SmallInt s1; double d = s1 + SmallInt(3.14); diff --git a/ch15/README.md b/ch15/README.md index f248032a..e7741b73 100644 --- a/ch15/README.md +++ b/ch15/README.md @@ -1,26 +1,32 @@ # Chapter 15. Object-Oriented Programming -## Exercise 15.1: +## Exercise 15.1 + > What is a virtual member? A member function should be dynamically bound by preceding its declaration. A virtual member in a base class expects its derived class define its own version. In particular base classes ordinarily should define a virtual destructor, even if it does no work. -## Exercise 15.2: +## Exercise 15.2 + > How does the `protected` access specifier differ from `private`? base class members: + - `private:`: base class itself and friends can access - `protected`: base class itself, friends and derived classes can access -## Exercise 15.3: +## Exercise 15.3 + > Define your own versions of the `Quote` class and the `print_total` function. [code](ex15_03_Quote.h) -## Exercise 15.4: +## Exercise 15.4 + > Which of the following declarations, if any, are incorrect? Explain why. + ```cpp class Base { ... }; (a) class Derived : public Derived { ... }; @@ -32,53 +38,63 @@ class Base { ... }; - (b) incorrect, this is a definition not a declaration - (c) incorrect, A derived class is declared like any other class. The declaration contains the class name but does not include its derivation list -## Exercise 15.5: +## Exercise 15.5 + > Define your own version of the `Bulk_quote` class. [code](ex15_05_Bulk_quote.h) -## Exercise 15.6: +## Exercise 15.6 + > Test your `print_total` function from the exercises in 15.2.1 (p. 595) by passing both `Quote` and `Bulk_quote` objects o that function. [TEST](TEST.cpp) -## Exercise 15.7: +## Exercise 15.7 + > Define a class that implements a limited discount strategy, which applies a discount to books purchased up to a given limit. If the number of copies exceeds that limit, the normal price applies to those purchased beyond the limit. [code](ex15_07_Limit_quote.h) -## Exercise 15.8: +## Exercise 15.8 + > Define static type and dynamic type. - static type: Type with which a variable is defined or that an expression yields. Static type is known at **compile time**. - dynamic type: Type of an object at **run time**. The dynamic type of an object to which a reference refers or to which a pointer points may differ from the static type of the reference or pointer. -## Exercise 15.9: +## Exercise 15.9 + > When is it possible for an expression’s static type to differ from its dynamic type? Give three examples in which the static and dynamic type differ. A pointer or reference to a base-class type can refer to an to object of derived type. In such cases the static type is reference (or pointer) to base, but the dynamic type is reference (or pointer) to derived. Anything like this can be an example. -## Exercise 15.10: +## Exercise 15.10 + > Recalling the discussion from 8.1 (p. 311), explain how the program on page 317 that passed an `ifstream` to the `Sales_data` `read` function works. the function takes a `istream` from which `ifstream` is derived. Hence the `ifstream` object "is a" `istream` ,which is why it works. -## Exercise 15.11: +## Exercise 15.11 + > Add a virtual `debug` function to your `Quote` class hierarchy that displays the data members of the respective classes. [Quote](ex15_11_Quote.h) | [Bulk_quote](ex15_11_Bulk_quote.h) | [Limit_quote](ex15_11_Limit_quote.h) -## Exercise 15.12: +## Exercise 15.12 + > Is it ever useful to declare a member function as both `override` and `final`? Why or why not? Sure. `override` means overriding the same name virtual function in base class. `final` means preventing any overriding this virtual function by any derived classes that are more lower at the hierarchy. (@Mooophy) -## Exercise 15.13: +## Exercise 15.13 + > Given the following classes, explain each print function: + ```cpp class base { public: @@ -94,17 +110,21 @@ private: int i; }; ``` + If there is a problem in this code, how would you fix it? The `print` in `derived::print` wanted to call the `print` from the base class. However, the class scope `base::` was omitted. As a result, it will cause an infinite recursion. **Fixed:** + ```cpp void print(ostream &os) { base::print(os); os << " " << i; } ``` -## Exercise 15.14: +## Exercise 15.14 + > Given the classes from the previous exercise and the following objects, determine which function is called at run time: + ```cpp base bobj; base *bp1 = &bobj; base &br1 = bobj; derived dobj; base *bp2 = &dobj; base &br2 = dobj; @@ -118,17 +138,20 @@ derived dobj; base *bp2 = &dobj; base &br2 = dobj; e and f are called at run time. -## Exercise 15.15: +## Exercise 15.15 + > Define your own versions of `Disc_quote` and `Bulk_quote`. [Disc_quote](ex15_15_Disc_quote.h) | [Bulk_quote](ex15_15_Bulk_quote.h) -## Exercise 15.16: +## Exercise 15.16 + > Rewrite the class representing a limited discount strategy, which you wrote for the exercises in 15.2.2 (p. 601), to inherit from `Disc_quote`. [code](ex15_16_Limit_quote.h) -## Exercise 15.17: +## Exercise 15.17 + > Try to define an object of type Disc_quote and see what errors you get from the compiler. ```sh @@ -137,8 +160,10 @@ note: because the following virtual functions are pure within 'ch15::EX15::Dis ^ ``` -## Exercise 15.18: +## Exercise 15.18 + > Given the classes from page 612 and page 613, and assuming each object has the type specified in the comments, determine which of these assignments are legal. Explain why those that are illegal aren’t allowed: + ```cpp Base *p = &d1; // d1 has type Pub_Derv -- legal p = &d2; // d2 has type Priv_Derv -- illegal @@ -151,23 +176,25 @@ p = &dd3; // dd3 has type Derived_from_Protected -- illegal ----- > **Assuming `D` inherits from `B`**: - +> > User code may use the derived-to-base conversion only if `D` inherits publicly from `B`. User code may not use the conversion if `D` inherits from `B` using either `protected` or `private`. -## Exercise 15.19: -> Assume that each of the classes from page 612 and page 613 has a member function of the form: +## Exercise 15.19 +> Assume that each of the classes from page 612 and page 613 has a member function of the form: +> >`void memfcn(Base &b) { b = *this; }` - +> > For each class, determine whether this function would be legal. ----- > **Assuming `D` inherits from `B`**: - +> > Member functions and friends of `D` can use the conversion to `B` **regardless of how** `D` inherits from `B`. The derived-to-base conversion to a direct base class is **always accessible** to members and friends of a derived class. Hence, the 3 below are all legal: + ```cpp Pub_Derv d1; // legal Priv_Derv d2; // legal @@ -177,18 +204,21 @@ Prot_Derv d3; // legal > Member functions and friends of classes derived from `D` may use the derived-to-base conversion if `D` inherits from `B` using **either `public` or `protected`**. Such code may not use the conversion if `D` inherits privately from `B`. Hence: + ```cpp Derived_from_Public dd1; // legal Derived_from_Private dd2; // illegal Derived_from_Protected dd3; // legal ``` -## Exercise 15.20: +## Exercise 15.20 + > Write code to test your answers to the previous two exercises. [code](ex15_20_Base.h) -## Exercise 15.21: +## Exercise 15.21 + > Choose one of the following general abstractions containing a family of types (or choose one of your own). Organize the types into an inheritance hierarchy: - (a) Graphical file formats (such as gif, tiff, jpeg, bmp) - (b) Geometric primitives (such as box, circle, sphere, cone) @@ -196,24 +226,28 @@ Derived_from_Protected dd3; // legal (b): [code](ex15_21_GeomtricPrimitives.h) -## Exercise 15.22: +## Exercise 15.22 + > For the class you chose in the previous exercise, identify some of the likely virtual functions as well as public and protected members. such as `shape_name()`, `resize_by_percentage(float pct)`, `area()`, `volume()`, etc. -## Exercise 15.23: +## Exercise 15.23 + > Assuming class `D1` on page 620 had intended to override its inherited `fcn` function, how would you fix that class? Assuming you fixed the class so that `fcn` matched the definition in `Base`, how would the calls in that section be resolved? [Fixed](ex15_23.cpp) -## Exercise 15.24: +## Exercise 15.24 + > What kinds of classes need a virtual destructor? What operations must a virtual destructor perform? Generally, a base class should define a virtual destructor. The destructor needs to be virtual to allow objects in the inheritance hierarchy to be **dynamically allocated**. -## Exercise 15.25: +## Exercise 15.25 + > Why did we define a default constructor for `Disc_quote`? What effect, if any, would removing that constructor have on the behavior of `Bulk_quote`? ```cpp @@ -262,7 +296,8 @@ int main() ``` Without it, when building the upper codes, the compiler would conplain that: -``` + +```sh error: use of deleted function 'Bulk_quote::Bulk_quote()' Bulk_quote b_quote; ^ @@ -273,18 +308,21 @@ error: use of deleted function 'Bulk_quote::Bulk_quote()' The reason is that a constructor taking 4 parameters has been defined, which prevented the compiler generate synthesized version default constructor. As a result, the default constructor of any class derived from it has been defined as deleted. Thus the default constructor must be defined explicitly so that the derived classes can call it when executing its default constructor. -## Exercise 15.26: +## Exercise 15.26 + > Define the `Quote` and `Bulk_quote` copy-control members to do the same job as the synthesized versions. Give them and the other constructors print statements that identify which function is running. Write programs using these classes and predict what objects will be created and destroyed. Compare your predictions with the output and continue experimenting until your predictions are reliably correct. - [Quote](ex15_26_Quote.h) - [Bulk_quote](ex15_26_Bulk_quote.h) -## Exercise 15.27: +## Exercise 15.27 + > Redefine your `Bulk_quote` class to inherit its constructors. [code](ex15_27_Bulk_quote.h) -## Exercise 15.28: +## Exercise 15.28 + > Define a `vector` to hold `Quote` objects but put `Bulk_quote` objects into that `vector`. Compute the total `net_price` of all the elements in the `vector`. ```cpp @@ -316,12 +354,13 @@ int main() **Output:** -``` +```sh bulk_quote's total: 325 total in the vector: 500 ``` -## Exercise 15.29: +## Exercise 15.29 + > Repeat your program, but this time store `shared_ptrs` to objects of type `Quote`. Explain any discrepancy in the sum generated by the this version and the previous program. If there is no discrepancy, explain why there isn’t one. ```cpp @@ -355,7 +394,7 @@ int main() **Output:** -``` +```sh bulk_quote's total: 325 total in the vector: 325 ``` @@ -366,13 +405,15 @@ If we want to holds objects related by inheritance, we should define the `vector Different from previous program, it can be found that 20% and 50% discount has been applied to the total price calculation. -## Exercise 15.30: +## Exercise 15.30 + > Write your own version of the `Basket` class and use it to compute prices for the same transactions as you used in the previous exercises. - [Basket](ex15_30_Basket.h) - [Quote & Bulk_quote](ex15_30_Quote_Bulk_quote.h) -## Exercise 15.31: +## Exercise 15.31 + > Given that `s1`, `s2`, `s3`, and `s4` are all `string`s, determine what objects are created in the following expressions: - (a) `Query(s1) | Query(s2) & ~ Query(s3);` - (b) `Query(s1) | (Query(s2) & ~ Query(s3));` @@ -382,7 +423,8 @@ Different from previous program, it can be found that 20% and 50% discount has b - (b): `WordQuery` -> `NotQuery` -> `AndQuery` -> `OrQuery` (same as the previous one) - (c): `WordQuery` -> `AndQuery` -> `OrQuery` -## Exercise 15.32: +## Exercise 15.32 + > What happens when an object of type `Query` is copied, moved, assigned, and destroyed? - **copy**: While being copied, the synthesized copy constructor is called. It copies the data member into the new object. Since in this case, the data member is a shared pointer, while copying, the corresponding shared pointer points to the same address and the use count from the both shared pointer becomes 2. @@ -395,7 +437,8 @@ Different from previous program, it can be found that 20% and 50% discount has b - **destroy**: The synthesized destructor will be called. It will call the destructor of `shared_ptr` which decrements the use count. If the count becomes zero, the destructor from `shared_ptr` will delete the resources it point to. -## Exercise 15.33: +## Exercise 15.33 + > What about objects of type `Query_base`? Managed by the synthesized version. Since `Query_base` a abstract class, the object of this type is essentially a sub-object of its derived class. diff --git a/ch16/README.md b/ch16/README.md index cd6e6679..a1957e74 100644 --- a/ch16/README.md +++ b/ch16/README.md @@ -1,22 +1,18 @@ -Chapter 16. Templates and Generic Programming -============================================= +# Chapter 16. Templates and Generic Programming -Exercise 16.1 --------------- +## Exercise 16.1 > Define instantiation. Class or function generated by the compiler from a template. -Exercise 16.2 --------------- +## Exercise 16.2 > Write and test your own versions of the `compare` functions. [compare](ex16_02_compare.h) -Exercise 16.3 --------------- +## Exercise 16.3 > Call your `compare` function on two `Sales_data` objects to see how your compiler handles errors during instantiation. @@ -24,43 +20,37 @@ Exercise 16.3 error C2678: binary '<': no operator found which takes a left-hand operand of type 'const Sales_data' (or there is no acceptable conversion) ``` -Exercise 16.4 --------------- +## Exercise 16.4 > Write a template that acts like the library `find` algorithm. The function will need two template type parameters, one to represent the function’s iterator parameters and the other for the type of the value. Use your function to find a given value in a `vector` and in a `list`. [Find](ex16_04_find.h) -Exercise 16.5 --------------- +## Exercise 16.5 > Write a template version of the `print` function from 6.2.4 (p. 217) that takes a reference to an array and can handle arrays of any size and any element type. [print](ex16_05_print_array.h) -Exercise 16.6 --------------- +## Exercise 16.6 > How do you think the library `begin` and `end` functions that take an array argument work? Define your own versions of these functions. [begin and end](ex16_06_begin_end.h) -Exercise 16.7 --------------- +## Exercise 16.7 > Write a `constexpr` template that returns the size of a given array. [SizeOfArray](ex16_07_sizeof_array.h) -Exercise 16.8 --------------- +## Exercise 16.8 > In the “Key Concept” box on page 108, we noted that as a matter of habit C++ programmers prefer using != to using <. Explain the rationale for this habit. As we’ve seen, only a few library types, `vector` and `string` being among them, have the subscript operator. Similarly, all of the library containers have iterators that define the `==` and `!=` operators. Most of those iterators do not have the `<` operator. By routinely using iterators and `!=`, we don’t have to worry about the precise type of container we’re processing. -Exercise 16.9 --------------- +## Exercise 16.9 > What is a function template? What is a class template? @@ -68,15 +58,13 @@ Exercise 16.9 - class template: Definition from which specific classes can be instantiated. - differ: the compiler cannot deduce the template parameter type(s) like function templates for a class template. we should supply the list of template arguments to use in place of the template parameters inside angle brackets following the template's name. -Exercise 16.10 ---------------- +## Exercise 16.10 > What happens when a class template is instantiated? the compiler **rewrites** the class template, **replacing each instance** of the template parameter `T` by the given template argument. -Exercise 16.11 ---------------- +## Exercise 16.11 > The following definition of `List` is incorrect. How would you fix it? > @@ -101,29 +89,25 @@ void insert(ListItem *ptr, elemType value); ListItem *front, *end; ``` -Exercise 16.12 ---------------- +## Exercise 16.12 > Write your own version of the `Blob` and `BlobPtr` templates. including the various `const` members that were not shown in the text. [`Blob`, `BlobPtr` and `ConstBlobPtr`](ex16_12_blob.h) | [Test](ex16_12_blob_test.cpp) -Exercise 16.13 ---------------- +## Exercise 16.13 > Explain which kind of friendship you chose for the equality and relational operators for `BlobPtr`. General friendship that each instantiation of `BlobPtr` grants access to the version of the equality and relational operators instantiated with the same type. -Exercise 16.14 ---------------- +## Exercise 16.14 > Write a `Screen` class template that uses nontype parameters to define the height and width of the `Screen`. [Screen](ex16_14_screen.h) | [Test](ex16_14_screen_test.cpp) -Exercise 16.15 ---------------- +## Exercise 16.15 > Implement input and output operators for your `Screen` template. Which, if any, friends are necessary in class `Screen` to make the input and output operators work? Explain why each friend declaration, if any, was needed. @@ -131,22 +115,19 @@ Exercise 16.15 same reason with `Blob`. -Exercise 16.16 ---------------- +## Exercise 16.16 > Rewrite the `StrVec` class (§ 13.5, p. 526) as a template named `Vec`. [Vec](ex16_16_vec.h) | [Test](ex16_16_vec_test.cpp) -Exercise 16.17 ---------------- +## Exercise 16.17 > What, if any, are the differences between a type parameter that is declared as a `typename` and one that is declared as a `class`? When must `typename` be used? When we want to inform the compiler that a name represents a type, we must use the keyword `typename`, not `class`. -Exercise 16.18 ---------------- +## Exercise 16.18 > Explain each of the following function template declarations and identify whether any are illegal. Correct each error that you find. > @@ -167,12 +148,10 @@ Fixed: (c) ``` -Exercise 16.19 ---------------- +## Exercise 16.19 > Write a function that takes a reference to a container and prints the elements in that container. Use the container’s `size_type` and `size` members to control the loop that prints the elements. -Exercise 16.20 ---------------- +## Exercise 16.20 > Rewrite the function from the previous exercise to use iterators returned from `begin` and `end` to control the loop. diff --git a/ch18/README.md b/ch18/README.md index 0b551012..ecefc2d7 100644 --- a/ch18/README.md +++ b/ch18/README.md @@ -1,35 +1,34 @@ -##Exercise 18.1 +# Chapter 18. Tools for Large Programs + +## Exercise 18.1 > What is the type of the exception object in the following throws? -> +> > **(a)**`range_error r("error");` > `throw r`; > **(b)**`exception *p = &r;` > `throw *P;` +> +> What would happen if the `throw` in **(b)** were written as `throw p`? ->What would happen if the `throw` in **(b)** were written as `throw p`? - - The type of the exception object in (a) is range_error which is used to report range errors in internal computations. - The type of the exception object in (b) is exception. - If the "throw" in (b) were written as "throw p", there will be a runtime error. - +The type of the exception object in (a) is range_error which is used to report range errors in internal computations. +The type of the exception object in (b) is exception. +If the "throw" in (b) were written as "throw p", there will be a runtime error. -##Exercise 18.2 +## Exercise 18.2 > Explain what happens if an exception occurs at the indicated point: - ```cpp void exercise(int *b, int *e) { - vector v(b,e); - int *p = new int[v.size()]; - ifstream in("ints"); - // exception occurs here + vector v(b,e); + int *p = new int[v.size()]; + ifstream in("ints"); + // exception occurs here } ``` The space "p" points will not be free. There will be a memory leak. -##Exercise 18.3 - +## Exercise 18.3