@@ -87,14 +87,14 @@ std::wstring utf8_to_wstring(std::string const &s) {
87
87
例如 ` 14 / 5 ` ,本来应该得到 2.8。但是因为 C 语言的除法返回 ` int ` ,结果会自动向下取整,导致得到 2。
88
88
89
89
``` cpp
90
- int a, b;
91
- int c = a / b;
90
+ int a = 14 , b = 5 ;
91
+ int c = a / b; // c = 14 / 5 = 3
92
92
```
93
93
94
94
等价于
95
95
96
96
``` cpp
97
- int c = floor((float )a / b);
97
+ int c = floor((float )a / b); // c = floor(2.8) = 3
98
98
```
99
99
100
100
如果 ` a ` 除以 ` b ` 除不尽,那么会找到比他大的第一个整数作为结果,这就是** 地板除 (floor div)** 。
@@ -135,27 +135,55 @@ int c = (a + b - 1) / b;
135
135
(10 + 5 - 1 ) / 5 = (10 + 4 ) / 5 = 14 / 5 = 2
136
136
```
137
137
138
- 这就是 C 语言中实现天花板除的业界公认标准方式 。
138
+ 这就是 C 语言中实现天花板除的业界公认方式 。
139
139
140
- ## 读取整个文件到字符串
140
+ ## 别再 ` [] ` 啦!
141
+
142
+ 你知道吗?在 map 中使用 ` [] ` 查找元素,如果不存在,会自动创建一个默认值。这个特性有时很方便,但如果你不小心写错了,就会在 map 中创建一个多余的默认元素。
141
143
142
144
``` cpp
143
- std::string file_get_content (std::string const &filename) {
144
- std::ifstream ifs(filename, std::ios::in | std::ios::binary);
145
- std::istreambuf_iterator<char > iit(ifs), iite;
146
- std::string content(iit, iite);
147
- return content;
148
- }
145
+ map<string, int > table;
146
+ table[" 小彭老师" ] = 24 ;
149
147
150
- void file_put_content(std::string const &filename, std::string const &content) {
151
- std::ofstream ofs(filename, std::ios::out | std::ios::binary);
152
- ofs << content;
148
+ cout << table[" 侯捷老师" ];
149
+ ```
150
+
151
+ table 中明明没有 "侯捷老师" 这个元素,但由于 ` [] ` 的特性,他会默认返回一个 0,不会爆任何错误!
152
+
153
+ 改用更安全的 ` at() ` 函数,当查询的元素不存在时,会抛出异常,方便你调试:
154
+
155
+ ``` cpp
156
+ map<string, int > table;
157
+ table.at(" 小彭老师" ) = 24 ;
158
+
159
+ cout << table.at(" 侯捷老师" ); // 抛出异常
160
+ ```
161
+
162
+ ` [] ` 真正的用途是“写入新元素”时,如果元素不存在,他可以自动帮你创建一个默认值,供你以引用的方式赋值进去。
163
+
164
+ 检测元素是否存在可以用 ` count ` :
165
+
166
+ ``` cpp
167
+ if (table.count(" 小彭老师" )) {
168
+ return table.at("小彭老师");
169
+ } else {
170
+ return 0;
153
171
}
154
172
```
155
173
156
- 这样就可以把整个文件读取到内存中,进行处理后再写回文件。
174
+ 即使你想要默认值 0 这一特性, ` count ` + ` at ` 也比 ` [] ` 更好,因为 ` [] ` 的默认值是会对 table 做破坏性修改的,这导致 ` [] ` 需要 ` map ` 的声明不为 ` const ` :
157
175
158
- > {{ icon.tip }} 推荐用 `std::ios::binary` 选项打开二进制文件,否则字符串中出现 `'\n'` 时,会被 MSVC 标准库自动转换成 `'\r\n'` 来写入,妨碍我们跨平台。
176
+ ``` cpp
177
+ map<string, int > table;
178
+ return table[" 小彭老师" ]; // 如果"小彭老师"这一键不存在,会创建"小彭老师"并设为默认值 0
179
+ ```
180
+
181
+ ``` cpp
182
+ const map<string, int > table;
183
+ return table[" 小彭老师" ]; // 编译失败![] 需要非 const 的 map 对象,因为他会破坏性修改
184
+ ```
185
+
186
+ > {{ icon.tip }} 更多 map 知识请看我们的 [ map 专题课] ( stl_map.md ) 。
159
187
160
188
## 别再写构造函数啦!
161
189
@@ -414,54 +442,6 @@ struct Class {
414
442
};
415
443
```
416
444
417
- ## 别再 `[]` 啦!
418
-
419
- 你知道吗?在 map 中使用 `[]` 查找元素,如果不存在,会自动创建一个默认值。这个特性有时很方便,但如果你不小心写错了,就会在 map 中创建一个多余的默认元素。
420
-
421
- ```cpp
422
- map<string, int> table;
423
- table["小彭老师"] = 24;
424
-
425
- cout << table["侯捷老师"];
426
- ```
427
-
428
- table 中明明没有 "侯捷老师" 这个元素,但由于 ` [] ` 的特性,他会默认返回一个 0,不会爆任何错误!
429
-
430
- 改用更安全的 ` at() ` 函数,当查询的元素不存在时,会抛出异常,方便你调试:
431
-
432
- ``` cpp
433
- map<string, int > table;
434
- table.at(" 小彭老师" ) = 24 ;
435
-
436
- cout << table.at(" 侯捷老师" ); // 抛出异常
437
- ```
438
-
439
- ` [] ` 真正的用途是“写入新元素”时,如果元素不存在,他可以自动帮你创建一个默认值,供你以引用的方式赋值进去。
440
-
441
- 检测元素是否存在可以用 ` count ` :
442
-
443
- ``` cpp
444
- if (table.count(" 小彭老师" )) {
445
- return table.at("小彭老师");
446
- } else {
447
- return 0;
448
- }
449
- ```
450
-
451
- 即使你想要默认值 0 这一特性,` count ` + ` at ` 也比 ` [] ` 更好,因为 ` [] ` 的默认值是会对 table 做破坏性修改的,这导致 ` [] ` 需要 ` map ` 的声明不为 ` const ` :
452
-
453
- ``` cpp
454
- map<string, int > table;
455
- return table[" 小彭老师" ]; // 如果"小彭老师"这一键不存在,会创建"小彭老师"并设为默认值 0
456
- ```
457
-
458
- ``` cpp
459
- const map<string, int > table;
460
- return table[" 小彭老师" ]; // 编译失败![] 需要非 const 的 map 对象,因为他会破坏性修改
461
- ```
462
-
463
- > {{ icon.tip }} 更多 map 知识请看我们的 [ map 专题课] ( stl_map.md ) 。
464
-
465
445
## 别再 make_pair 啦!
466
446
467
447
``` cpp
@@ -900,6 +880,56 @@ T square(T x) {
900
880
}
901
881
```
902
882
883
+ ## 读取整个文件到字符串
884
+
885
+ ```cpp
886
+ std::string file_get_content(std::string const &filename) {
887
+ std::ifstream ifs(filename, std::ios::in | std::ios::binary);
888
+ std::istreambuf_iterator<char> iit(ifs), iite;
889
+ std::string content(iit, iite);
890
+ return content;
891
+ }
892
+
893
+ void file_put_content(std::string const &filename, std::string const &content) {
894
+ std::ofstream ofs(filename, std::ios::out | std::ios::binary);
895
+ ofs << content;
896
+ }
897
+ ```
898
+
899
+ 这样就可以把整个文件读取到内存中,很方便地进行处理后再写回文件。
900
+
901
+ > {{ icon.tip }} 推荐用 ` std::ios::binary ` 选项打开二进制文件,否则字符串中出现 ` '\n' ` 时,会被 MSVC 标准库自动转换成 ` '\r\n' ` 来写入,妨碍我们跨平台。
902
+
903
+ ## 逐行读取文本文件
904
+
905
+ ``` cpp
906
+ std::ifstream fin ("test.txt");
907
+ std::string line;
908
+ while (std::getline(fin, line)) {
909
+ std::cout << "读取到一行:" << line << '\n';
910
+ }
911
+ ```
912
+
913
+ ## 字符串切片
914
+
915
+ ```cpp
916
+ #include <sstream>
917
+ #include <string>
918
+ #include <vector>
919
+
920
+ std::vector<std::string> split_str(std::string const &str, char ch) {
921
+ std::stringstream ss(str);
922
+ std::string line;
923
+ std::vector<std::string> res;
924
+ while (std::getline(ss, line, ch)) {
925
+ res.push_back(std::move(line));
926
+ }
927
+ return res;
928
+ }
929
+
930
+ auto res = split_str("hello world", ' '); // res = {"hello", "world"}
931
+ ```
932
+
903
933
## cout 不需要 endl
904
934
905
935
``` cpp
@@ -1952,6 +1982,8 @@ int b = f >> 4; // 0x2
1952
1982
1953
1983
## 多线程通信应基于队列,而不是共享全局变量
1954
1984
1955
- ## RAII 的 finally
1985
+ ## RAII 的 finally 帮手类
1956
1986
1957
1987
## swap 缩小 mutex 区间代价
1988
+
1989
+ ## namespace 别名
0 commit comments