Keep working

master
Jason Zhu 2020-10-17 09:25:58 +11:00
parent ef8119bc1a
commit f329878ce2
16 changed files with 1078 additions and 0 deletions

1
.gitignore vendored 100644
View File

@ -0,0 +1 @@
.vscode

3
.gitmodules vendored 100644
View File

@ -0,0 +1,3 @@
[submodule "Cpp-Primer"]
path = Cpp-Primer
url = https://github.com/Mooophy/Cpp-Primer.git

1
Cpp-Primer 160000

@ -0,0 +1 @@
Subproject commit 1d15633aac9c57f973451d16d01adedf8850627d

BIN
part_i/ch03_4_1 100755

Binary file not shown.

View File

@ -0,0 +1,26 @@
#include <string>
#include <iostream>
using std::string; using std::cout; using std::endl;
int main(int argc, char const *argv[])
{
string s("some string");
// if (s.begin() != s.end())
// {
// auto it = s.begin();
// *it = toupper(*it);
// }
for (auto it = s.begin(); it != s.end() && !isspace(*it); ++it)
{
*it = toupper(*it); // capitalize the current character
}
cout << (s) << endl;
return 0;
}

View File

@ -0,0 +1,58 @@
# Chapter 4. Expressions
* C++ provides set of operators
* Also define what these operators do when applied to built-type operand
* **Expression** consists of single/multi operands. When evaluated, it yields a result
## 4.1 Fundamentals
## 4.2 Arithmetic Operators
## 4.3 Logical and Relational Operators
## 4.4 Assignment Operators
## 4.5 Increment and Decrement Operators
## 4.6 The Member Access Operators
* `.` & `->` operators provide member access.
* `.` get member from an object of class type
* `->` dereference then get member; `ptr->mem` is synonum for `(*ptr).mem`
* `.` has higher precedence than dereference (i.e. ->)
```cpp
// run the size member of p, then dereference the result!
*p.size(); // error: p is a pointer and has no member named size
```
## 4.7 The Conditional Operator
## 4.8 The Bitwise Operators
## 4.9 The sizeof Operator
* **sizeof** operator returns size (in bytes) of **an expression** or **a type name**.
* It's right associative
* Result of `sizeof` is a constant expression of type `size_t`
* Syntax of `sizeof`:
* For type name: `sizeof (type)`
* For expression: `sizeof expr`
* `sizeof` doesn't evaluate its operand
```cpp
Sales_data data, *p;
sizeof(Sales_data); // size required to hold an object of type Sales_data
sizeof data; // size of data's type, i.e., sizeof(Sales_data)
sizeof p; // size of a pointer
sizeof *p; // size of the type to which p points, i.e., sizeof(Sales_data)
sizeof data.revenue; // size of the type of Sales_data's revenue member
sizeof Sales_data::revenue; // alternative way to get the size of revenue
```
## 4.10 Comma Operator
## 4.11 Type Conversions
## 4.12 Operator Precedence Table

View File

@ -0,0 +1,137 @@
# Chapter 5. Statements
## 5.1 Simple Statements
## 5.2 Statement Scope
## 5.3 Conditional Statements
## 5.4 Iterative Statements
### 5.4.1 The `while` Statement
### 5.4.2 Traditional for Statement
### 5.4.3 Range `for` Statement (C++11)
**range for statement**: simpler `for` statement that used to iterate through elements of an container
Syntax:
```cpp
for (declaration : expression)
statement
```
* where *expression* must be a sequence
* *declaration* defines a variable. Every element in sequence must be converted into declaration
* Hence, `auto` type specifier is best
```cpp
vector<int> v = {0,1,2,3,4,5,6,7,8,9};
// range variable must be a reference so we can write to the elements
for (auto &r : v) // for each element in v, as we want to change r, we declare it as reference
r *= 2; // double the value of each element in v
```
which equivalent to
```cpp
for (auto beg = v.begin(), end = v.end(); beg != end; ++beg) {
auto &r = *beg; // r must be a reference so we can change the element
r *= 2; // double the value of each element in v
}
```
Q: Why cannot use a range `for` to add elements to a `vector`
A: In a range `for`, the value of `end()` is cached. If add elements to sequence, the value of `end()` will be invalidated.
### 5.4.4 The do while Statement
## 5.5 Jump Statements
### 5.5.1 The `break` Statement
### 5.5.2 The `continue` Statement
### 5.5.3 The `goto` Statement
???
## 5.6 `try` Blocks and Exception Handling
* **throw expressions**: the part which the detecting part uses to indicate that it encountered sth run-time error
* **try blocks**: code blocks are run, from where exception may occue
* starts with `try` and ends with multiple **catch clause**
* Exceptions thrown from code executed inside a `try` block are handled by one of `cath` clauses.
* `catch` clauses are also called **exception handler**
### 5.6.1 A `throw` Expression
Syntax of `throw` Expression: keyword `throw` followed by an expression.
e.g. convert following to code snippet with `throw`
```cpp
Sales_item item1, item2;
cin >> item1 >> item2;
// first check that item1 and item2 represent the same book
if (item1.isbn() == item2.isbn()) {
cout << item1 + item2 << endl;
return 0; // indicate success
} else {
cerr << "Data must refer to same ISBN"
<< endl;
return -1; // indicate failure
}
```
equivalent with throw expression. Rewrite the test to throw an exception rather than returning an error indicator
```cpp
// first check that the data are for the same item
if (item1.isbn() != item2.isbn())
throw runtime_error("Data must refer to same ISBN");
// if we're still here, the ISBNs are the same
cout << item1 + item2 << endl;
```
* Throwing an exception terminates the current function and transfers control to a handler that know how to handle this error.
* `runtime_error` is one of std library exception types, defined in `stdexcept` header.
### 5.6.2 The `try` Block
general form of `try` block
```cpp
try {
program-statements
} catch (exception-declaration) {
handler-statements
} catch (exception-declaration) {
handler-statements
} // . . .
```
???
### 5.6.3 Standard Exceptions
Exception classed defined in std library, defined in 4 headers:
1. `exception` header: most general exception class.
1. Only show exception occur, no additional info
2. `stdexcept` header: some general-purpose exception classes, as shown in table
3. `new` header: `bad_alloc` exception type, detailed in Chapter 12.1.2
4. `type_info` header: `bad_cast` exception type, detailed in Chapter 19.2
| std exception classes in `<stdexcept>` | Description |
| -------------------------------------- | -------------------------------- |
| `exception` | Most general kind of problem |
| `runtime_error` | Problem detected only at runtime |
| `range_error` | Run-time error: ??? |
??? Not finished ???

View File

@ -0,0 +1,58 @@
# Chapter 6. Functions
## 6.1 Function Basics
## 6.2 Argument Passing
???
### 6.2.1 Passing Arguments by Value
### 6.2.2 Passing Arguments by Reference
### 6.2.3 `const` Parameters and Arguments
### 6.2.4 Array Parameters
### 6.2.5 `main`: Handling Command-Line Options
### 6.2.6 Functions with Varying Parameters
## 6.3 Return Types and the return Statement
## 6.4 Overloaded Functions
## 6.5 Features for Specialized Uses
???
### 6.5.1 Default Arguments
### 6.5.2 Inline and `constexpr` Functions
### 6.5.3 Aids for Debugging
## 6.6 Function Matching
???
#### Determining the Candidate and Viable Functions
#### Finding the Best Match, If Any
#### Function Matching with Multiple Parameters
### 6.6.1 Argument Type Conversions
## 6.7 Pointers to Functions
???
#### Using Function Pointers
#### Pointers to Overloaded Functions
#### Function Pointer Parameters
#### Returning a Pointer to Function
#### Use `auto` or `decltype` for Function Pointer Types

View File

@ -0,0 +1,7 @@
# Chapter 7. Classes
## 7.1 Defining Abstract Data Types
## 7.2 Access Control and Encapsulation
## 7.3 Additional Class Features

View File

@ -0,0 +1,498 @@
# Chapter 2. Variables and Basic Types
## 2.3 Compound Types
A **Compound type** is a data type that's defined using another data type. (e.g. **reference** & **pointers**)
* A declaration of data: **base type** followed by a list of **declarators**.
* Simple declaration: declarator are just variable name
### 2.3.1 References
Note: After reading the book, I use [Reference declaration from cppreference.com](https://en.cppreference.com/w/cpp/language/reference) for better explanation
Reference declaration declares a named variable as a **reference**, that is, an alias to an already-existing object or function.
2 kinds of reference variable declaration:
* Lvalue reference
* Rvalue reference (check chapter 13.6.1)
**reference** (usually means "lvalue reference") declaration syntax: `S& D;`, declares declarator D as an `lvalue reference` to type determined by S
```cpp
int ival = 1024;
int &refVal = ival; // refVal refers to (is another name for) ival
int &refVal2; // error: a reference must be initialized
```
* When decleared/initizlied, the reference is bound to the initialized object
* After declaration, all operation on reference are operated on bounded obj
```cpp
refVal = 2 // assigns 2 to the object to which refVal refers, i.e., to ival
int ii = refVal; // same as ii = ival
```
### 2.3.2 Pointers
A **pointer** is a compound type "points to" another data type:
* Like reference: pointers are used for indirect access
* Unlike reference: pointer itself is an object. Hence, it can be reassigned/copied. No need to be initialized when declared
Pointer declaration: `S* D`, where declares declarator D as a pointer to the type determined by S; `*` needed for each pointer variable
```cpp
int *ip1, *ip2; // both ip1 and ip2 are pointers to int
double dp, *dp2; // dp2 is a pointer to double; dp is a double
```
#### Taking the address of an Object
Pointer hold address of another obj. Address are obtained using `&`
```cpp
int ival = 42;
int *p = &ival; // p holds the address of ival; p is a pointer to ival
```
* Reference are not obj => they don't have address.
* Type of pointer & obj must match
```cpp
double dval;
double *pd = &dval; // ok: initializer is the address of a double
double *pd2 = pd; // ok: initializer is a pointer to double
int *pi = pd; // error: types of pi and pd differ
pi = &dval; // error: assigning the address of a double to a pointer to int
```
#### Pointer Value (states)
Pointer value can be in 4 states:
1. Point to an obj
2. Point to the location just immediately past the end of an obj
3. Point to null; i.e. bound to none
4. Invalid; values other than preceding 3; these pointers generate error
#### Using a Pointer to Access Obj
**Dereference operator** (`*` operator):
```cpp
int ival = 42;
int *p = &ival; // p holds the address of ival; p is a pointer to ival
cout << *p; // * yields the object to which p points; prints 42
```
#### Null Pointers
* **Null Pointer** points to no one.
* Developer can check whether a pointer pointing to NULL.
Multiple values to be assigned as null:
* `nullptr`: most directed, introduced in C++11
* `0`
* `NULL`: a **preprocessor variable** used by older programes, defined in `cstdlib` header. Replaced by preprocessor before compilation.
```cpp
int *p1 = nullptr; // equivalent to int *p1 = 0;
int *p2 = 0; // directly initializes p2 from the literal constant 0
// must #include cstdlib
int *p3 = NULL; // equivalent to int *p3 = 0;
```
* **Advice: Initialize all Pointers**. Uninitialized pointers are common source of run-time errors.
* Difference btw reference & pointer:
* reference is not obj; must be initalized; cannot be reassigned
#### `void*` Pointers
`void*` is a special pointer type that can hold address of any object. Type of the object at that address is unknown:
```cpp
double obj = 3.14, *pd = &obj;
// ok: void* can hold the address value of any data pointer type
void *pv = &obj; // obj can be an object of any type
pv = pd; // pv can hold a pointer to any type
```
Utility of `void*` pointer:
* Compare it to another pointer
* Pass it to or return it from a function
* Assign it to another `void*` pointer
Details are covered in Chapter 19.1.1
### 2.3.3 Understanding Compound Type Declarations
A variable definition consists of a base type and a list of declarators. Each declarator can relate its variable to the base type differently from others. e.g. shown below
```cpp
// i is an int; p is a pointer to int; r is a reference to int
int i = 1024, *p = &i, &r = i;
```
#### Defining Multiple Variables
It's easy to be confused and think type modifier applies to all variables
```cpp
int* p; // legal but might be misleading
```
```cpp
int* p1, p2; // p1 is a pointer to int; p2 is an int
```
#### Pointers to Pointers
A pointer is an object in memory, so like any object it also has an address.
* `**` for a pointer to a pointer
* `***` for a pointer to a pointer to a pointer
```cpp
int ival = 1024;
int *pi = &ival; // pi points to an int
int **ppi = &pi; // ppi points to a pointer to an int
```
Dereferencing also will be cascaded
```cpp
cout << "The value of ival\n"
<< "direct value: " << ival << "\n"
<< "indirect value: " << *pi << "\n"
<< "doubly indirect value: " << **ppi
<< endl;
```
#### References to Pointers
As a pointer is an object, we can define a reference to a pointer:
```cpp
int i = 42;
int *p; // p is a pointer to int
int *&r = p; // r is a reference to the pointer p
r = &i; // r refers to a pointer; assigning &i to r makes p point to i
*r = 0; // dereferencing r yields i, the object to which p points; changes i to 0
```
Way to understand: read `r` right to left; `*&r` means the r is a reference that refer to a pointer.
## 2.4 CONST Qualifier
* Defining the variable's type as **const**
* const object must be initialized when creation.
```cpp
const int i = get_size(); // ok: initialized at run time
const int j = 42; // ok: initialized at compile time
const int k; // error: k is uninitialized const
```
#### Initialization** and `const`
* `const` types has restriction in terms of operations it allows
```cpp
int i = 42;
const int ci = i; // ok: the value in i is copied into ci
int j = ci; // ok: the value in ci is copied into j
```
#### By Default, `const` Objects Are Local to a File
* Compiler will replace const objects during compilation
* Hence, compiler need to know variable's initializer during compilation (not run time)
* Hence, variable must be defined in every file that wants to use the value
* So, normally, same name with `const` in multiple files are separate.
Q: How to share `const` across multiple files? i.e. Define the `const` in 1 file, and declare it in other files to use it?
A: add `extern` on both definition & declaration
```cpp
// file_1.cc defines and initializes a const that is accessible to other files
extern const int bufSize = fcn();
// file_1.h
extern const int bufSize; // same bufSize as defined in file_1.cc
```
### 2.4.1 Reference to `const`
Q: How to bind a reference to an object of a `const` type.
A: use **reference to const**: a reference to a `const` type. As it's bound to a const, it cannot be used to change value
Syntax of reference to const: `const int &D`
```cpp
const int ci = 1024;
const int &r1 = ci; // ok: both reference and underlying object are const
r1 = 42; // error: r1 is a reference to const
int &r2 = ci; // error: non const reference to a const object
```
#### Initialization and Reference to `const`
Exception to be noted:
1. We can bind a **reference to const** to a **nonconst object**: When we bind a reference to an object of different type, compiler will transform the RHS to a proper data type to fit LHS (e.g. create a temporary `const int temp` that equal to float value, then reference to that temporary value)
1. Normally don't do that
```cpp
double dval = 3.14;
const int &ri = dval;
const int &ri = dval;
//equal to
const int temp = dval;
const int &ri = temp
```
#### A Reference to `const` May Refer to an Obj that's not `const`
Binding a **reference to const** to an object only restrict the operation we can do on reference, not the underlying obj itself.
```cpp
int i = 42;
int &r1 = i; // r1 bound to i
const int &r2 = i; // r2 also bound to i; but cannot be used to change i
r1 = 0; // r1 is not const; i is now 0
r2 = 0; // error: r2 is a reference to const
```
### 2.4.2 Pointers and `const`
* **Pointer to const** cannot be used to change the object.
* Only can store the address of a `const` object in a **pointer to `const` (i.e. const pointer)**
Syntax: `const S *D = &`
```cpp
const double pi = 3.14; // pi is const; its value may not be changed
double *ptr = &pi; // error: ptr is a plain pointer
const double *cptr = &pi; // ok: cptr may point to a double that is const
*cptr = 42; // error: cannot assign to *cptr
```
Notes:
1. we can store a nonconst object's address in a **pointer to const**
It's helpful to think of **pointers** & **references** to `const` as pointers or references "that think they point or refer to `const`."
#### `const` Pointers
A pointer can also be `const`. Syntax: `const double *const pip`
???
### 2.4.3 Top-Level `const`
* **top-level const**: pointer itself is `const`
* **low-level const**: pointer point to a `const` object
???
### 2.4.4 `constexpr` and Constant Expressions
* **Constant expression** = an expression whose value cannot change & can be evaluated at compile time.
* e.g.
* literal
* `const` object initialized from constant expression
```cpp
const int max_files = 20; // max_files is a constant expression
const int limit = max_files + 1; // limit is a constant expression
int staff_size = 27; // staff_size is not a constant expression
const int sz = get_size(); // sz is not a constant expression
```
#### `constexpr` Variables (C++11)
In large system, whether an initializer is a constant expression is hard to determine. Hence, we can ask compiler to verify whether a variable is constant expression using `constexpr` declaration.
```cpp
constexpr int mf = 20; // 20 is a constant expression
constexpr int limit = mf + 1; // mf + 1 is a constant expression
constexpr int sz = size(); // ok only if size is a constexpr function
```
After C++11, It's best practice to use `constexpr` instead of `const`
#### Literal Types
**Literal Types** = types we can use in a `constexpr`
Types known are literal types:
* arithmetic
* reference
* pointer types
* `nullptr` or `0` as constant expression
* Address of an obj defined outside function (check 6.1.1)
Not literal:
* variable ordinarily defined inside function (check 6.1.1)
#### Pointers and `constexpr`
When define a pointer in a `constexpr` declaration, it applies to pointer not underlying obj
```cpp
const int *p = nullptr; // p is a pointer to a const int
constexpr int *q = nullptr; // q is a const pointer to int
```
a `constexpr` pointer maynot point to a `const` type:
```cpp
constexpr int *np = nullptr; // np is a constant pointer to int that is null
int j = 0;
constexpr int i = 42; // type of i is const int
// i and j must be defined outside any function
constexpr const int *p = &i; // p is a constant pointer to the const int i
constexpr int *p1 = &j; // p1 is a constant pointer to the int j
```
## 2.5 Dealing With Types
Complicated program results to complicated types:
1. Some types are tedious/lengthy form
2. Hard to determine the exact type we need.
### 2.5.1 Type Aliases
**Type Alias** = a name that's a synoym for another type. So we can simplify complicated type name.
Two way of definition:
1. `typedef`: traditional
2. **alias declaration**: since c++11
Syntax of **typedef**:
```cpp
typedef double wages; // wages is a synonym for double
typedef wages base, *p; // base is a synonym for double, p for double*
```
* declarator can include type modifiers (`&` `*`) to form compound type
Syntax for **alias declaration**:
```cpp
using SI = Sales_item; // SI is a synonym for Sales_item
```
After definition of type alias, it is used as a type name and can appear wherever a type name is:
```cpp
wages hourly, weekly; // same as double hourly, weekly;
SI item; // same as Sales_item item
```
#### Pointers, `const` and Type Aliases
Mixed type modifier and type aliases together
```cpp
typedef char *pstring; // pstring is an alis for type char*
const pstring cstr = 0; // cstr is a constant pointer to char
const pstring *ps; // ps is a pointer to a constant pointer to char
```
* type of `pstring` is "pointer to char"
* type of `const pstring` is a "constant pointer to char", not a pointer to `const char`
???
### 2.5.2 The `auto` Type Specifier (C++11)
* Sometimes, it's impossible to determine the type of an expression when writing it.
* `auto` type specifier from C++11 tell compiler to **deduce the type from initializer**.
* variable use `auto` must have an initializer
```cpp
// the type of item is deduced from the type of the result of adding val1 and val2
auto item = val1 + val2; // item initialized to the result of val1 + val2
```
Multiple variable declaration using `auto`:
```cpp
auto i = 0, *p = &i; // ok: i is int and p is a pointer to int
auto sz = 0, pi = 3.14; // error: inconsistent types for sz and pi
```
#### Compound Types, `const` and `auto`
* When use reference as initializer for `auto`, compiler use underlying object's type for `auto`'s type deduction
```cpp
int i = 0, &r = i;
auto a = r; // a is an int (r is an alias for i, which has type int)
```
* `auto` normally ignores top-level const, while low-level const (e.g. an initializer is a pointer to const) are kept
```cpp
const int ci = i, &cr = ci; // ci is constant integer, cr is a reference to constant integer (low-level)
auto b = ci; // b is an int (top-level const in ci is dropped)
auto c = cr; // c is an int (cr is an alias for ci whose const is top-level)
auto d = &i; // d is an int*(& of an int object is int*)
auto e = &ci; // e is const int*(& of a const object is low-level const)
```
??? Concepts are confusing ???
### 2.5.3 The `decltype` Type Specifier
Type specifier **decltype** returns type of its operand (i.e. compiler deduces from expression but don't use the expression to initialize variable)
```cpp
decltype(f()) sum = x; // sum has whatever type f returns
```
Explain:
* compiler doesn't call `f`, but uses the type that such a call would return as type for `sum`
How `decltype` handles **top-level const** and **reference**: returns type of that variable, including top-level const and references:
```cpp
const int ci = 0, &cj = ci;
decltype(ci) x = 0; // x has type const int
decltype(cj) y = x; // y has type const int& and is bound to x
decltype(cj) z; // error: z is a reference and must be initialized
```
#### `decltype` and References
`decltype` is the only context in which a variable defined as a reference is not treated as synonym for the referred object
`decltype` returns a reference type for expression that yield objects that can stand on LHS of assignment
```cpp
// decltype of an expression can be a reference type
int i = 42, *p = &i, &r = i;
decltype(r + 0) b; // ok: addition yields an int; b is an (uninitialized) int
decltype(*p) c; // error: c is int& and must be initialized
```
* `decltype(r)` returns a reference type
* If we want the type of referred object, use `r` in an expression (e.g. `r+0`)
* `decltype(*p)` returns a reference, must be initialized ????
??? Not Finished ???

View File

@ -0,0 +1,216 @@
# Chapter 3. Strings, Vectors, and Arrays
## 3.3 Library vector Type
* **vector** = collection of objs (all have same type)
* **vector** is a **container** (it "contains" other objects). Detail of containers are in Part II
* Include correct header and `using` declaration before using `vector`:
```cpp
#include <vector>
using std::vector;
```
* **vector** is a **class template** (Details are introduced in Chapter 13)
* Template are not functions or classes. But can be used to generating classes or functions.
* Process of creating classes/func from template is **instantiation**
* Specify which class to instantiate by `template_name<> obj_name` (C++11 standard)
```cpp
vector<int> ivec; // ivec holds objects of type int
vector<Sales_item> Sales_vec; // holds Sales_items
vector<vector<string>> file; // vector whose elements are vectors
```
Note:
* `vector` is template, not a type.
* Types generated from `vector` must include element type (e.g. `vector<int>`)
???
## 3.4 Introducing Iterators
Two ways of access containers (i.e. vector):
1. subscripts
2. **iterators**
All containers from library have iterators, but not all of them support subscript operator.
* iterator provide indirect access like pointers
* iterator can be valid/invalid
### 3.4.1 Using Iterators
* Containers have members to return iterator: `begin` & `end`
* `begin` returns an iterator denotes the 1st element:
* `end` return an iterator positioned "one past the end" of container (i.e. it's nonexistent element "off the end")
* iterator returned by `end` often referred to **off-the-end iterator** or **end iterator**
* If container is empty: `begin` `end`'s iterator are same
```cpp
// the compiler determines the type of b and e; see § 2.5.2 (p. 68)
// b denotes the first element and e denotes one past the last element in v
auto b = v.begin(), e = v.end(); // b and e have the same type
```
For best practice:
* Normally, we don't (want to) know the precise type of iterator. We Hence use `auto` to let compiler decide.
#### Iterator Operations
| operator | Description |
| ----------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `*iter` | Returns a reference to the element denoted by iterator |
| `iter->mem` | Dereference iter and fetches the member named `mem` from the underlying element. Equivalent to (*iter).mem |
| `++iter` | Increments `iter` to refer to next element |
| `--iter` | Decrements `iter` to refer to previous element |
| `iter1 == iter2` ; `iter1 != iter2` | Compares 2 iterators, they are equal if denoting same element or they are end iterator of same container |
* Here `*iter` return a reference is actually deference the iterator (like pointer's operation).
Following code transfer the first char to upper letter:
```cpp
string s("some string");
if (s.begin() != s.end()) { // make sure s is not empty
auto it = s.begin(); // it denotes the first character in s
*it = toupper(*it); // make that character uppercase, dereference it via `*it`
}
```
* We dereference `it` to pass the current char to `toupper` and assign the resulting uppercase letter back to into character denoted by `it`
#### Moving Iterators from One Element to Another
* `++/--` in/decrement operators are used to move iterators from one element to next.
* end-iterator does not denote an element, it cannot be incremented & dereferenced.
```c++
// process characters in s until we run out of characters or we hit a whitespace
for (auto it = s.begin(); it != s.end() && !isspace(*it); ++it)
*it = toupper(*it); // capitalize the current character
```
* This code stop at whitespace
**Key Concept: Generic Programming**
* C++ programmers use `!=` as habit
* Only few library types have subscript operator, all library containers have iterators that defined `==` & `!=`. Most of them does not have `<`
#### Iterator Types
* We generally don't need to know the precise type of an iterator (like we use `auto` for vector's `size_type` member)
* Iterators from library types have `iterator` & `const_iterator` type
```cpp
vector<int>::iterator it; // it can read and write vector<int> elements
string::iterator it2; // it2 can read and write characters in a string
vector<int>::const_iterator it3; // it3 can read but not write elements
string::const_iterator it4; // it4 can read but not write characters
```
Terminology confusion: Iterators and Iterator Types
* "iterator" refers to 3 entities:
* 1. *concept* of an iterator
* 2. `iterator` *type* defined by an container
* 3. *object*
* Every container class defines a type named `iterator`; it supports actions
#### `begin` and `end` Operation
If object returned by `begin` & `end` are `const`, then type returned by `begin`/`end` are const
```cpp
vector<int> v;
const vector<int> cv; // cv is a vector with constant integer
auto it1 = v.begin(); // it1 has type vector<int>::iterator
auto it2 = cv.begin(); // it2 has type vector<int>::const_iterator
```
As shown above, the type are varying. C++11 gave **`cbegin`** & **`cend`** functions to specify type
```cpp
auto it3 = v.cbegin(); // it3 has type vector<int>::const_iterator
```
#### Combining Dereference and Member Access
Correct way of dereference iterator and access members:
* **`(xx)` for `(*it)` is required**. It means apply dereference operator to `it` and to apply dot operator to the result of dereferencing `it`.
```cpp
(*it).empty()
```
* Incorrect usage:
* Iterator has no members
```cpp
(*it).empty() // dereferences it and calls the member empty on the resulting object
*it.empty() // error: attempts to fetch the member named empty from it
// but it is an iterator and has no member named empty
```
Simplified dereference & member access:
* **`->` operator**;
```cpp
// print each line in text up to the first blank line
for (auto it = text.cbegin(); it != text.cend() && !it->empty(); ++it)
cout << *it << endl;
```
Currently remember loops that use iterators should not add elements to the container to which the iterator refer
### 3.4.2 Iterator Arithmetic
Operations suppoted by vector and string Iterators
| Operator | Description |
| -------------------------- | ------------------------------------------------------------------------ |
| `iter +/- n` | generate a iterator that many elements forward/backward within container |
| `iter += n` or `iter -= n` | Compound-assignment for iterator addition/subtraction |
| `iter1 - iter2` | yields the number |
| `>`, `>=`, `<`, `<=` | A iterator < other means it appears before |
```cpp
// compute an iterator to the element closest to the midpoint of vi
auto mid= vi.begin() + vi.size() / 2;
```
```cpp
if (it < mid)
// process elements in the first half of vi
```
??? Skip ???
#### Using Iterator Arithmetic
Binary search using iterator arithmetic
```cpp
// text must be sorted
// beg and end will denote the range we're searching
auto beg = text.begin(), end = text.end();
auto mid = text.begin() + (end - beg)/2; // original midpoint
// while there are still elements to look at and we haven't yet found sought
while (mid != end && *mid != sought) {
if (sought < *mid) // is the element we want in the first half?
end = mid; // if so, adjust the range to ignore the second half
else // the element we want is in the second half
beg = mid + 1; // start looking with the element just after mid
mid= beg + (end - beg)/2; // new midpoint
}
```
* At end of `while`, `mid` will be equal to `end` or it will denote the element for which we are looking.

BIN
part_i/ex3_23 100755

Binary file not shown.

32
part_i/ex3_23.cpp 100644
View File

@ -0,0 +1,32 @@
#include <vector>
#include <iostream>
using std::vector;
using std::cout; using std::endl;
int main(int argc, char const *argv[])
{
vector<int> v{0,2,5,1,3,6,9,10,4,2};
cout << "Original vector: ";
for (auto it = v.cbegin(); it != v.cend(); ++it)
{
cout << *it << " ";
}
cout << endl;
cout << "Modified vector: ";
for (auto it = v.begin(); it != v.end(); ++it)
{
*it = *it * 2;
cout << *it << " ";
}
cout << endl;
return 0;
}

View File

@ -0,0 +1,11 @@
# Chapter 8. The IO Library
* C++ use various types in std IO libraries to handle IO.
List of C++ classes to handle IO:
* `istream` (input stream) type, for input operations
* `ostream` (output stream) type, for output operations
* `cin` (an `istream` obj) reads std input
* `cout`
* `cerr` (an `ostream` obj) for program error messages, writes to std error

View File

@ -0,0 +1,27 @@
# Chapter 13. Copy Control
Advanced topic for class constructors/desctructors
Copy Control = operations of following:
* **Copy- & Move- constructor**: define what happens when an object is initialized from another object of the same type
* **Copy- & Move- assignment**: define what happens when we assign an object (class A) to object (class B)
* **Destructor**: define what happens when object of type A destroyed
When Copy Controls are not cleared defined, C++ compiler automatically create them; -> undefined behavior
## 13.1 Copy, Assign, And Destroy
### 13.1.1 Copy Constructor
```cpp
class Foo {
public:
Foo(); // default constructor
Foo(const Foo&); // copy constructor
// ...
};
```
* copy constructor's 1st parameter is a reference to the class type
* copy constructor's other parameters have default values

View File

@ -0,0 +1,3 @@
#!/bin/bash
docker run --rm -it -v "$(pwd)":/usr/src gcc