@@ -87,14 +87,14 @@ std::wstring utf8_to_wstring(std::string const &s) {
8787例如 ` 14 / 5 ` ,本来应该得到 2.8。但是因为 C 语言的除法返回 ` int ` ,结果会自动向下取整,导致得到 2。
8888
8989``` 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
9292```
9393
9494等价于
9595
9696``` cpp
97- int c = floor((float )a / b);
97+ int c = floor((float )a / b); // c = floor(2.8) = 3
9898```
9999
100100如果 ` a ` 除以 ` b ` 除不尽,那么会找到比他大的第一个整数作为结果,这就是** 地板除 (floor div)** 。
@@ -135,27 +135,55 @@ int c = (a + b - 1) / b;
135135(10 + 5 - 1 ) / 5 = (10 + 4 ) / 5 = 14 / 5 = 2
136136```
137137
138- 这就是 C 语言中实现天花板除的业界公认标准方式 。
138+ 这就是 C 语言中实现天花板除的业界公认方式 。
139139
140- ## 读取整个文件到字符串
140+ ## 别再 ` [] ` 啦!
141+
142+ 你知道吗?在 map 中使用 ` [] ` 查找元素,如果不存在,会自动创建一个默认值。这个特性有时很方便,但如果你不小心写错了,就会在 map 中创建一个多余的默认元素。
141143
142144``` 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 ;
149147
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;
153171}
154172```
155173
156- 这样就可以把整个文件读取到内存中,进行处理后再写回文件。
174+ 即使你想要默认值 0 这一特性, ` count ` + ` at ` 也比 ` [] ` 更好,因为 ` [] ` 的默认值是会对 table 做破坏性修改的,这导致 ` [] ` 需要 ` map ` 的声明不为 ` const ` :
157175
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 ) 。
159187
160188## 别再写构造函数啦!
161189
@@ -414,54 +442,6 @@ struct Class {
414442};
415443```
416444
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-
465445## 别再 make_pair 啦!
466446
467447``` cpp
@@ -900,6 +880,56 @@ T square(T x) {
900880}
901881```
902882
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+
903933## cout 不需要 endl
904934
905935``` cpp
@@ -1952,6 +1982,8 @@ int b = f >> 4; // 0x2
19521982
19531983## 多线程通信应基于队列,而不是共享全局变量
19541984
1955- ## RAII 的 finally
1985+ ## RAII 的 finally 帮手类
19561986
19571987## swap 缩小 mutex 区间代价
1988+
1989+ ## namespace 别名
0 commit comments