Skip to content

Commit 06737bc

Browse files
committed
minor update
1 parent c4e8768 commit 06737bc

File tree

2 files changed

+45
-48
lines changed

2 files changed

+45
-48
lines changed

docs/cpp_lifetime.md

+4
Original file line numberDiff line numberDiff line change
@@ -176,3 +176,7 @@ int main() {
176176
- `-Wdelete-non-virtual-dtor`
177177

178178
TODO: 介绍
179+
180+
## 临时变量的生命周期
181+
182+
TODO

docs/cpp_tricks.md

+41-48
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,18 @@ std::wstring utf8_to_wstring(std::string const &s) {
8080
}
8181
```
8282

83+
## 读取整个文件到字符串
84+
85+
```cpp
86+
TODO
87+
```
88+
89+
## 位域(bit-field)
90+
91+
```cpp
92+
TODO
93+
```
94+
8395
## 别再写构造函数啦!
8496

8597
```cpp
@@ -874,7 +886,7 @@ int res = bound(5, 6); // 等价于 func(6, 1, 5, w);
874886
875887
这是一个绑定器,把 `func` 的第二个参数和第四个参数固定下来,形成一个新的函数对象,然后只需要传入前面两个参数就可以调用原来的函数了。
876888
877-
这是一个非常旧的技术,C++11 时代就有了。但是,现在有了 Lambda 表达式,可以更简洁地实现:
889+
这是一个非常旧的技术,C++98 时代就有了。但是,现在有了 Lambda 表达式,可以更简洁地实现:
878890
879891
```cpp
880892
int func(int x, int y, int z, int &w);
@@ -898,6 +910,8 @@ Lambda 表达式有许多优势:
898910
auto lambda = [&w](int x, int y) { return func(y + 8, 1, x * x, ++w) * 2; };
899911
```
900912
913+
### bind 的历史
914+
901915
为什么 C++11 有了 Lambda 表达式,还要提出 `std::bind` 呢?
902916
903917
虽然 bind 和 lambda 看似都是在 C++11 引入的,实际上 bind 的提出远远早于 lambda。
@@ -945,6 +959,8 @@ void some_func(int i1, int i2, int i3, int i4);
945959
946960
> {{ icon.fun }} 所以,现在还坚持用 bind 的,都是些 2005 年前后在象牙塔接受 C++ 教育,但又不肯“终身学习”的劳保。这批劳保又去“上岸”当“教师”,继续复制 2005 年的错误毒害青少年,实现了劳保的再生产。
947961
962+
### thread 膝盖中箭
963+
948964
糟糕的是,bind 的这种荼毒,甚至影响到了线程库:`std::thread` 的构造函数就是基于 `std::bind` 的!
949965

950966
这导致了 `std::thread``std::bind` 一样,无法捕获引用。
@@ -975,7 +991,7 @@ t.join();
975991
printf("%d\n", x); // 42
976992
```
977993

978-
最后再举个绑定随机数生成器例子:
994+
### 举个绑定随机数生成器例子
979995

980996
```cpp
981997
std::mt19937 gen(seed);
@@ -1049,7 +1065,7 @@ void some_func(auto &&arg) {
10491065
10501066
少了烦人的尖括号,看起来容易懂多了。
10511067
1052-
> {{ icon.tip }} 但是,这里有一个问题,为什么 `std::forward` 要写成 `std::forward<T>` 的形式呢?为什么不是 `std::forward(t)` 呢?因为这样写的话,`forward` 也没法知道你的 `t` 是左是右了(函数参数始终会默认推导为左,即使定义的 `t` 是右)因此必须告诉 `forward`,`t` 的定义类型,也就是 `T`,或者通过 `decltype(t)` 来获得 `T`。
1068+
> {{ icon.detail }} 但是,我们同学有一个问题,为什么 `std::forward` 要写成 `std::forward<T>` 的形式呢?为什么不是 `std::forward(t)` 呢?因为这样写的话,`forward` 也没法知道你的 `t` 是左是右了(函数参数始终会默认推导为左,即使定义的 `t` 是右)因此必须告诉 `forward`,`t` 的定义类型,也就是 `T`,或者通过 `decltype(t)` 来获得 `T`。
10531069
10541070
总之,如果你用的是 `auto &&` 参数,那么 `FWD` 会很方便(自动帮你 `decltype`)。但是如果你用的是模板参数 `T &&`,那么 `FWD` 也可以用,因为 `decltype(t)` 总是得到 `T`。
10551071
@@ -1064,7 +1080,7 @@ struct Class {
10641080
}
10651081
10661082
void hello() {
1067-
auto memfn = std::bind(&Class::world, this); // 将 this->world 绑定成一个函数对象
1083+
auto memfn = std::bind(&Class::world, this); // 将 this->world 绑定成一个可以延后调用的函数对象
10681084
memfn();
10691085
memfn();
10701086
}
@@ -1089,7 +1105,7 @@ struct Class {
10891105
}
10901106
```
10911107

1092-
问题是,当我们的成员函数含有多个参数时,bind 就非常麻烦了需要一个个写出 placeholder,而且数量必须和 `world` 的参数数量一致。每次 `world` 要新增参数时,都需要加一下 placeholder,非常沙雕。
1108+
bind 的缺点是,当我们的成员函数含有多个参数时,bind 就非常麻烦了需要一个个写出 placeholder,而且数量必须和 `world` 的参数数量一致。每次 `world` 要新增参数时,所有 bind 的地方都需要加一下 placeholder,非常沙雕。
10931109

10941110
```cpp
10951111
struct Class {
@@ -1128,7 +1144,7 @@ struct Class {
11281144
}
11291145
```
11301146

1131-
而 C++14 起 lambda 支持变长参数,就没有这么死板
1147+
而 C++14 起 lambda 支持了变长参数,就不用这么死板
11321148

11331149
```cpp
11341150
struct Class {
@@ -1150,7 +1166,7 @@ struct Class {
11501166
}
11511167
```
11521168

1153-
更好的是配合 `FWD` 宏实现参数的完美转发:
1169+
更好的是配合上文提到的 `FWD` 宏实现参数的完美转发:
11541170

11551171
```cpp
11561172
struct Class {
@@ -1562,28 +1578,10 @@ if (auto it = table.find(key); it != table.end()) {
15621578
}
15631579
```
15641580

1565-
## 检测是否存在指定成员函数
1566-
1567-
TODO
1568-
1569-
## 位域(bit-field)
1570-
15711581
## map + any 外挂属性
15721582

1573-
## vector + unordered_map = LRU cache
1574-
1575-
## 多线程通信应基于队列,而不是共享全局变量
1576-
15771583
## 自定义 shared_ptr 的 deleter
15781584

1579-
## 读取整个文件
1580-
1581-
## RAII 的 finally
1582-
1583-
## swap 缩小 mutex 区间代价
1584-
1585-
## Lambda 捕获 unique_ptr 导致 function 报错怎么办
1586-
15871585
## CHECK_CUDA 类错误检测宏
15881586

15891587
## 函数默认参数求值的位置是调用者
@@ -1593,32 +1591,13 @@ TODO
15931591
## 花括号实现安全的类型转换检查
15941592

15951593
## 成员函数针对 this 的移动重载
1596-
## 位域(bit-field)
1597-
1598-
## vector + unordered_map = LRU cache
1599-
1600-
## 多线程通信应基于队列,而不是共享全局变量
1601-
1602-
## 自定义 shared_ptr 的 deleter
1603-
1604-
## 读取整个文件到字符串
1605-
1606-
## RAII 的 finally
1607-
1608-
## swap 缩小 mutex 区间代价
1609-
1610-
## Lambda 捕获 unique_ptr 导致 function 报错怎么办
16111594

16121595
## CHECK_CUDA 类错误检测宏
16131596

16141597
## 函数默认参数求值的位置是调用者
16151598

1616-
## 设置 locale 为 .utf8
1617-
16181599
## 花括号实现安全的类型转换检查
16191600

1620-
## 成员函数针对 this 的移动重载
1621-
16221601
## 临时右值转左值
16231602

16241603
C++ 有个特性:支持纯右值(prvalue)隐式转换成 const 的左值引用。
@@ -1671,10 +1650,24 @@ func(temporary(1));
16711650
16721651
> {{ icon.story }} 在 Libreoffice 源码中就有应用这个帮手函数。
16731652
1674-
## 临时变量的生命周期是一行
1653+
> {{ icon.warn }} 临时变量的生命周期是一行
16751654
1676-
TODO
1655+
## ADL 机制
1656+
1657+
## shared_from_this
1658+
1659+
## requires 语法检测是否存在指定成员函数
16771660
1678-
### ADL 机制
1661+
## 设置 locale 为 .utf8 解决编码问题
1662+
1663+
## 成员函数针对 this 的移动重载
16791664
1680-
### `shared_from_this`
1665+
<!-- ## vector + unordered_map = LRU cache -->
1666+
<!-- -->
1667+
<!-- ## Lambda 捕获 unique_ptr 导致 function 报错怎么办 -->
1668+
<!-- -->
1669+
<!-- ## 多线程通信应基于队列,而不是共享全局变量 -->
1670+
<!-- -->
1671+
<!-- ## RAII 的 finally -->
1672+
<!-- -->
1673+
<!-- ## swap 缩小 mutex 区间代价 -->

0 commit comments

Comments
 (0)