Keep working
parent
ef8119bc1a
commit
f329878ce2
|
@ -0,0 +1 @@
|
|||
.vscode
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "Cpp-Primer"]
|
||||
path = Cpp-Primer
|
||||
url = https://github.com/Mooophy/Cpp-Primer.git
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 1d15633aac9c57f973451d16d01adedf8850627d
|
Binary file not shown.
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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
|
|
@ -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 ???
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
# Chapter 7. Classes
|
||||
|
||||
## 7.1 Defining Abstract Data Types
|
||||
|
||||
## 7.2 Access Control and Encapsulation
|
||||
|
||||
## 7.3 Additional Class Features
|
|
@ -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 = π // 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 = π // error: ptr is a plain pointer
|
||||
const double *cptr = π // 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 ???
|
|
@ -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.
|
||||
|
Binary file not shown.
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
docker run --rm -it -v "$(pwd)":/usr/src gcc
|
Loading…
Reference in New Issue