cplusplus-primer-5ed-notes/part_i/chap3_strings_vectors_and_a...

217 lines
8.1 KiB
Markdown
Raw Normal View History

2020-10-17 09:25:58 +11:00
# 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.