Skip to content

Commit f869d7f

Browse files
committed
Update public notes
1 parent 6d195f5 commit f869d7f

File tree

4 files changed

+158
-1
lines changed

4 files changed

+158
-1
lines changed
269 KB
Loading
121 KB
Loading
135 KB
Loading

content/编程相关/编程语言/Cpp 之旅 第三版 读书笔记.md

Lines changed: 158 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1570,6 +1570,163 @@ v.emplace_back(1, "build in place"); // 就地构造
15701570
15711571
### 迭代器
15721572
1573+
pass
15731574
1575+
### 迭代器类型
1576+
*迭代器的本质是什么?*
15741577
1575-
#todo
1578+
省流:迭代器是一个泛型,也是一个 concept. 符合迭代器特征的都是迭代器.
1579+
1580+
用户很少知道特定迭代器的类型,容器知道自己迭代器的类型,并且以规范定义的 `iterator` 和 `const_iterator` 给用户使用。
1581+
1582+
有些情况下,迭代器不是成员类型,所以标准库提供了 `iterator_t<X>` 函数来统一接口,对定义的迭代器类型 `X` 可用。
1583+
1584+
#### 流迭代器
1585+
1586+
`istream_iterator<>` `ostream_iterator<>`
1587+
1588+
### 使用谓词
1589+
*这回真是谓词了,函数式的那种。*
1590+
1591+
```cpp
1592+
void f(map<string,int>& m) {
1593+
auto p = find_if(m, Greater_than{42}); // 谓词 Greater_than{}.
1594+
}
1595+
```
1596+
1597+
Greater_than 是函数对象.
1598+
1599+
```cpp
1600+
struct Greater_than {
1601+
int val;
1602+
Greater_then(int v) : val{v} {}
1603+
bool operator() (const pair<string,int>& r) const {
1604+
return r.second > val;
1605+
}
1606+
}
1607+
```
1608+
1609+
匿名函数也可以.
1610+
1611+
```cpp
1612+
auto p = find_if(m [](const auto& r) { return r.second > 42 });
1613+
```
1614+
1615+
### 标准库算法概览
1616+
1617+
*懒得全部记完,记一些特殊的.*
1618+
1619+
| name | note |
1620+
| ---------------------------- | ----------------------------------------------- |
1621+
| for_each | 遍历执行 f(x) |
1622+
| find_if | 如果满足 f(x) |
1623+
| count_if | 计数和if |
1624+
| replace_if | |
1625+
| copy_if | |
1626+
| move | |
1627+
| unique_copy | 不拷贝连续重复元素 |
1628+
| sort | 可以多加一个 f(x) 谓词作为排序标准 |
1629+
| `(p1,p2)=equal_range(b,e,v)` | `[pl:p2)是已排序序列[b:e)的子序列,其中元素的值都等于v:本质上等价于二分搜索v` |
1630+
| merge | 归并序列,并将归并序列存到新序列。可以加 f(x) 作为比较函数 |
1631+
1632+
每个算法都有 `<range>` 版本.
1633+
1634+
算法会修改元素的值,但是不会添加和删除元素,因为序列并不包含底层容器的信息(*算法操作的是迭代器,不知道实际用的是什么容器*)。如果要添加删除,得自己手动直接操作容器。
1635+
1636+
尽可能使用它们编写程序,而不是从头另起炉灶。
1637+
1638+
### 并行算法
1639+
1640+
有两种执行方式:
1641+
1642+
- 并行执行:任务在多线程中完成。
1643+
- 数组化执行(向量化执行):在单线程用 SIMD 完成。
1644+
1645+
`<execution>` 中有命名空间 execution,会有如下参数:
1646+
1647+
- seq 顺序执行
1648+
- par 如果可能,则并行执行
1649+
- unseq 非顺序(数组化) 执行 如果可能
1650+
- par_unseq 并行执行和数组化执行 如果可能
1651+
1652+
考虑根据硬件使用并行算法。
1653+
1654+
```cpp
1655+
sort(par_unseq, v.begin(), v.end());
1656+
```
1657+
1658+
### 建议
1659+
1660+
- 搜索的时候,通常返回输入序列的末尾位置来表示未找到。
1661+
- 使用 using 类型别名清理杂乱的符号。 *当然不是让你在全局作用域用 using。*
1662+
1663+
## 第14章 范围
1664+
*range 实际上也是概念.*
1665+
1666+
range 有如下定义方式:
1667+
1668+
- 一对 bgein end 迭代器
1669+
- 一对 bgein n,n是元素个数
1670+
- 一对 bgein pred,pred 是谓词,如果 `pred(p)` 为真,则表示达到了范围末端。
1671+
1672+
### 视图
1673+
1674+
> 视图是查看范围的一种方式.
1675+
1676+
```cpp
1677+
filter_view v {r, [](int x) { return x%2; }}; // 查看 r 中的奇数
1678+
for (int x : v)
1679+
cout << x << ' ';
1680+
```
1681+
1682+
类似还有 `take_view`,也就是拿前几个。
1683+
1684+
可以不写名字直接玩视图嵌套。 *函数式管道:初现端倪*
1685+
1686+
```cpp
1687+
for (int x : take_view{ filter_view {r, [](int x) { return x%2; } } , 3})
1688+
cout << x << ' ';
1689+
```
1690+
1691+
![[Pasted image 20251110153452.png]]
1692+
1693+
不抄了,自己看。
1694+
1695+
视图和范围很相似,但区别在于 **视图不拥有元素本身**,释放范围的元素责任在范围身上。所以视图的生命周期不能大于范围的生命周期。
1696+
1697+
视图复制开小很低,可以用值传递。
1698+
1699+
### 生成器
1700+
*范围工厂.*
1701+
1702+
![[Pasted image 20251110154016.png]]
1703+
1704+
*itoa_view 就类似 python 的 range 了,可以生成数字序列。*
1705+
1706+
### 管道
1707+
1708+
```cpp
1709+
for (int x : r | views::filter(odd) | views::take(3)) // odd 是谓词
1710+
cout << x << ' ';
1711+
```
1712+
1713+
管道从左至右执行。
1714+
1715+
这些过滤器函数定义在 `ranges::views` 中.
1716+
1717+
> 视图和管道的实现涉及一些令人毛骨悚然的模板元编程,如果你对性能表示担忧,请确保先对你实现的性能进行测量,确定其是否符合需求。如果不符合,可以用传统的替代方案来实现。
1718+
1719+
*我听劝,我不看怎么实现的了。*
1720+
1721+
### 概念概述
1722+
*怎么跑这章来了.*
1723+
1724+
![[Pasted image 20251110154632.png]]
1725+
1726+
*多少有点过于魔法了,用到我再记吧.*
1727+
1728+
### 建议
1729+
1730+
- 如果迭代器对的样子变得冗长,用范围版本算法
1731+
- 理想的类型应满足 relugar 概念。
1732+
- 尽可能使用标准库的概念。

0 commit comments

Comments
 (0)