Skip to content

Commit 0309aec

Browse files
committed
deploy: 7419b95
1 parent 182d9fd commit 0309aec

File tree

5 files changed

+181
-67
lines changed

5 files changed

+181
-67
lines changed

cpp_tricks/index.html

Lines changed: 97 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,11 @@
268268
<ul class="nav flex-column">
269269
</ul>
270270
</li>
271-
<li class="nav-item" data-bs-level="2"><a href="#_7" class="nav-link">提前返回</a>
271+
<li class="nav-item" data-bs-level="2"><a href="#_7" class="nav-link">继承构造函数</a>
272+
<ul class="nav flex-column">
273+
</ul>
274+
</li>
275+
<li class="nav-item" data-bs-level="2"><a href="#_8" class="nav-link">提前返回</a>
272276
<ul class="nav flex-column">
273277
</ul>
274278
</li>
@@ -320,15 +324,15 @@
320324
<ul class="nav flex-column">
321325
</ul>
322326
</li>
323-
<li class="nav-item" data-bs-level="2"><a href="#_8" class="nav-link">读取整个文件到字符串</a>
327+
<li class="nav-item" data-bs-level="2"><a href="#_9" class="nav-link">读取整个文件到字符串</a>
324328
<ul class="nav flex-column">
325329
</ul>
326330
</li>
327-
<li class="nav-item" data-bs-level="2"><a href="#_9" class="nav-link">逐行读取文本文件</a>
331+
<li class="nav-item" data-bs-level="2"><a href="#_10" class="nav-link">逐行读取文本文件</a>
328332
<ul class="nav flex-column">
329333
</ul>
330334
</li>
331-
<li class="nav-item" data-bs-level="2"><a href="#_10" class="nav-link">字符串切片</a>
335+
<li class="nav-item" data-bs-level="2"><a href="#_11" class="nav-link">字符串切片</a>
332336
<ul class="nav flex-column">
333337
</ul>
334338
</li>
@@ -344,7 +348,7 @@
344348
<ul class="nav flex-column">
345349
</ul>
346350
</li>
347-
<li class="nav-item" data-bs-level="2"><a href="#_11" class="nav-link">智能指针防止大对象移动</a>
351+
<li class="nav-item" data-bs-level="2"><a href="#_12" class="nav-link">智能指针防止大对象移动</a>
348352
<ul class="nav flex-column">
349353
</ul>
350354
</li>
@@ -368,7 +372,7 @@
368372
<ul class="nav flex-column">
369373
</ul>
370374
</li>
371-
<li class="nav-item" data-bs-level="2"><a href="#_13" class="nav-link">救命!为什么我的全局函数不能作为函数对象?</a>
375+
<li class="nav-item" data-bs-level="2"><a href="#_14" class="nav-link">救命!为什么我的全局函数不能作为函数对象?</a>
372376
<ul class="nav flex-column">
373377
</ul>
374378
</li>
@@ -384,15 +388,15 @@
384388
<ul class="nav flex-column">
385389
</ul>
386390
</li>
387-
<li class="nav-item" data-bs-level="2"><a href="#_14" class="nav-link">函数默认参数求值的位置是调用者</a>
391+
<li class="nav-item" data-bs-level="2"><a href="#_15" class="nav-link">函数默认参数求值的位置是调用者</a>
388392
<ul class="nav flex-column">
389393
</ul>
390394
</li>
391395
<li class="nav-item" data-bs-level="2"><a href="#locale-utf8" class="nav-link">设置 locale 为 .utf8</a>
392396
<ul class="nav flex-column">
393397
</ul>
394398
</li>
395-
<li class="nav-item" data-bs-level="2"><a href="#_15" class="nav-link">花括号实现安全的类型转换检查</a>
399+
<li class="nav-item" data-bs-level="2"><a href="#_16" class="nav-link">花括号实现安全的类型转换检查</a>
396400
<ul class="nav flex-column">
397401
</ul>
398402
</li>
@@ -404,15 +408,15 @@
404408
<ul class="nav flex-column">
405409
</ul>
406410
</li>
407-
<li class="nav-item" data-bs-level="2"><a href="#_16" class="nav-link">函数默认参数求值的位置是调用者</a>
411+
<li class="nav-item" data-bs-level="2"><a href="#_17" class="nav-link">函数默认参数求值的位置是调用者</a>
408412
<ul class="nav flex-column">
409413
</ul>
410414
</li>
411-
<li class="nav-item" data-bs-level="2"><a href="#_17" class="nav-link">花括号实现安全的类型转换检查</a>
415+
<li class="nav-item" data-bs-level="2"><a href="#_18" class="nav-link">花括号实现安全的类型转换检查</a>
412416
<ul class="nav flex-column">
413417
</ul>
414418
</li>
415-
<li class="nav-item" data-bs-level="2"><a href="#_18" class="nav-link">临时右值转左值</a>
419+
<li class="nav-item" data-bs-level="2"><a href="#_19" class="nav-link">临时右值转左值</a>
416420
<ul class="nav flex-column">
417421
</ul>
418422
</li>
@@ -452,7 +456,7 @@
452456
<ul class="nav flex-column">
453457
</ul>
454458
</li>
455-
<li class="nav-item" data-bs-level="2"><a href="#_19" class="nav-link">多线程通信应基于队列,而不是共享全局变量</a>
459+
<li class="nav-item" data-bs-level="2"><a href="#_20" class="nav-link">多线程通信应基于队列,而不是共享全局变量</a>
456460
<ul class="nav flex-column">
457461
</ul>
458462
</li>
@@ -485,7 +489,8 @@ <h1 id="c">应知应会 C++ 小技巧</h1>
485489
<li><a href="#_4">别再 [] 啦!</a></li>
486490
<li><a href="#_5">别再写构造函数啦!</a></li>
487491
<li><a href="#_6">别再写拷贝构造函数啦!</a></li>
488-
<li><a href="#_7">提前返回</a></li>
492+
<li><a href="#_7">继承构造函数</a></li>
493+
<li><a href="#_8">提前返回</a></li>
489494
<li><a href="#lambda">立即调用的 Lambda</a></li>
490495
<li><a href="#lambda_1">Lambda 复用代码</a></li>
491496
<li><a href="#inline">类内静态成员 inline</a></li>
@@ -498,35 +503,35 @@ <h1 id="c">应知应会 C++ 小技巧</h1>
498503
<li><a href="#c_1">C++ 随机数的正确生成方式</a></li>
499504
<li><a href="#const">const 居然应该后置&hellip;</a></li>
500505
<li><a href="#auto">函数参数也可以 auto</a></li>
501-
<li><a href="#_8">读取整个文件到字符串</a></li>
502-
<li><a href="#_9">逐行读取文本文件</a></li>
503-
<li><a href="#_10">字符串切片</a></li>
506+
<li><a href="#_9">读取整个文件到字符串</a></li>
507+
<li><a href="#_10">逐行读取文本文件</a></li>
508+
<li><a href="#_11">字符串切片</a></li>
504509
<li><a href="#cout-endl">cout 不需要 endl</a></li>
505510
<li><a href="#cout">多线程中 cout 出现乱序?</a></li>
506511
<li><a href="#cerr-cout">cerr 与 cout 的抉择</a></li>
507-
<li><a href="#_11">智能指针防止大对象移动</a></li>
512+
<li><a href="#_12">智能指针防止大对象移动</a></li>
508513
<li><a href="#optional">optional 实现延迟初始化</a></li>
509514
<li><a href="#if-auto-while-auto">if-auto 与 while-auto</a></li>
510515
<li><a href="#bind-lambda">bind 是历史糟粕,应该由 Lambda 表达式取代</a><ul>
511516
<li><a href="#bind">bind 的历史</a></li>
512517
<li><a href="#thread">thread 膝盖中箭</a></li>
513-
<li><a href="#_12">举个绑定随机数生成器例子</a></li>
518+
<li><a href="#_13">举个绑定随机数生成器例子</a></li>
514519
</ul>
515520
</li>
516521
<li><a href="#forward-fwd">forward 迷惑性地不好用,建议改用 FWD 宏</a></li>
517522
<li><a href="#bind-lambda-bind_front">bind 绑定成员函数是陋习,改用 lambda 或 bind_front</a></li>
518-
<li><a href="#_13">救命!为什么我的全局函数不能作为函数对象?</a></li>
523+
<li><a href="#_14">救命!为什么我的全局函数不能作为函数对象?</a></li>
519524
<li><a href="#map-any">map + any 外挂属性</a></li>
520525
<li><a href="#shared_ptr-deleter">自定义 shared_ptr 的 deleter</a></li>
521526
<li><a href="#check_cuda">CHECK_CUDA 类错误检测宏</a></li>
522-
<li><a href="#_14">函数默认参数求值的位置是调用者</a></li>
527+
<li><a href="#_15">函数默认参数求值的位置是调用者</a></li>
523528
<li><a href="#locale-utf8">设置 locale 为 .utf8</a></li>
524-
<li><a href="#_15">花括号实现安全的类型转换检查</a></li>
529+
<li><a href="#_16">花括号实现安全的类型转换检查</a></li>
525530
<li><a href="#this">成员函数针对 this 的移动重载</a></li>
526531
<li><a href="#check_cuda_1">CHECK_CUDA 类错误检测宏</a></li>
527-
<li><a href="#_16">函数默认参数求值的位置是调用者</a></li>
528-
<li><a href="#_17">花括号实现安全的类型转换检查</a></li>
529-
<li><a href="#_18">临时右值转左值</a></li>
532+
<li><a href="#_17">函数默认参数求值的位置是调用者</a></li>
533+
<li><a href="#_18">花括号实现安全的类型转换检查</a></li>
534+
<li><a href="#_19">临时右值转左值</a></li>
530535
<li><a href="#ostringstream">ostringstream 格式化字符串</a></li>
531536
<li><a href="#adl">ADL 机制实现静态多态</a></li>
532537
<li><a href="#shared_from_this">shared_from_this</a></li>
@@ -536,7 +541,7 @@ <h1 id="c">应知应会 C++ 小技巧</h1>
536541
<li><a href="#bit-field">位域(bit-field)</a></li>
537542
<li><a href="#vector-unordered_map-lru-cache">vector + unordered_map = LRU cache</a></li>
538543
<li><a href="#lambda-unique_ptr-function">Lambda 捕获 unique_ptr 导致 function 报错怎么办</a></li>
539-
<li><a href="#_19">多线程通信应基于队列,而不是共享全局变量</a></li>
544+
<li><a href="#_20">多线程通信应基于队列,而不是共享全局变量</a></li>
540545
<li><a href="#raii-finally">RAII 的 finally 帮手类</a></li>
541546
<li><a href="#swap-mutex">swap 缩小 mutex 区间代价</a></li>
542547
<li><a href="#namespace">namespace 别名</a></li>
@@ -756,7 +761,61 @@ <h2 id="_6">别再写拷贝构造函数啦!</h2>
756761
<p>总之,很多 C++ 教材把拷贝/移动构造函数过于夸大,搞得好像每个类都需要自己定义一样。</p>
757762
<p>实际上,只有在“自己实现容器”的情况下,才需要自定义拷贝构造函数。可是谁会整天手搓容器?</p>
758763
<p>大多数情况下,我们只需要在类里面存 vector、string 等封装好的容器,编译器默认生成的拷贝构造函数会自动调用他们的拷贝构造函数,用户只需专注于业务逻辑即可,不需要操心底层细节。</p>
759-
<h2 id="_7">提前返回</h2>
764+
<p>对于持有资源的 RAII 类,我们都会直接删除其拷贝构造函数和拷贝赋值函数:</p>
765+
<pre><code class="language-cpp">struct RAIIHandle {
766+
int handle;
767+
RAIIHandle() {
768+
handle = CreateObject();
769+
}
770+
RAIIHandle(RAIIHandle const &amp;) = delete;
771+
RAIIHandle &amp;operator=(RAIIHandle const &amp;) = delete;
772+
RAIIHandle() {
773+
DeleteObject(handle);
774+
}
775+
};
776+
</code></pre>
777+
<h2 id="_7">继承构造函数</h2>
778+
<p>C++ 特色:子类不会自动继承父类的构造函数!(除非父类的构造函数是没有参数的默认构造函数)</p>
779+
<pre><code class="language-cpp">struct Parent {
780+
Parent(int age, const char *name) { ... }
781+
void parent_func() { ... }
782+
};
783+
784+
struct Child : Parent {
785+
void child_func() { ... }
786+
};
787+
788+
Child child(23, &quot;peng&quot;); // 错误!Child 没有构造函数!
789+
</code></pre>
790+
<p>可以在子类里面写 <code>using 父类::父类</code>,就能自动继承父类所有的构造函数了。</p>
791+
<pre><code class="language-cpp">struct Parent {
792+
Parent(int age, const char *name) { ... }
793+
void parent_func() { ... }
794+
};
795+
796+
struct Child : Parent {
797+
using Parent::Parent; // 加上这一行!
798+
void child_func() { ... }
799+
};
800+
801+
Child child(23, &quot;peng&quot;); // 编译通过,自动调用到父类的构造函数 Parent(int, const char *)
802+
</code></pre>
803+
<p>在 C++98 中,没有 using 的这个语法,只能自己定义一个构造函数,然后使用“委任构造”的语法转发所有参数给父类,非常繁琐。</p>
804+
<pre><code class="language-cpp">struct Parent {
805+
Parent(int age, const char *name) { ... }
806+
void parent_func() { ... }
807+
};
808+
809+
struct Child : Parent {
810+
Child(int age, const char *name)
811+
: Parent(age, name)
812+
{ ... }
813+
void child_func() { ... }
814+
};
815+
816+
Child child(23, &quot;peng&quot;); // 编译通过,调用到子类的构造函数后转发到父类
817+
</code></pre>
818+
<h2 id="_8">提前返回</h2>
760819
<pre><code class="language-cpp">void babysitter(Baby *baby) {
761820
if (!baby-&gt;is_alive()) {
762821
puts(&quot;宝宝已经去世了&quot;);
@@ -1174,7 +1233,7 @@ <h2 id="auto">函数参数也可以 auto</h2>
11741233
return x * x;
11751234
}
11761235
</code></pre>
1177-
<h2 id="_8">读取整个文件到字符串</h2>
1236+
<h2 id="_9">读取整个文件到字符串</h2>
11781237
<pre><code class="language-cpp">std::string file_get_content(std::string const &amp;filename) {
11791238
std::ifstream ifs(filename, std::ios::in | std::ios::binary);
11801239
std::istreambuf_iterator&lt;char&gt; iit(ifs), iite;
@@ -1191,14 +1250,14 @@ <h2 id="_8">读取整个文件到字符串</h2>
11911250
<blockquote>
11921251
<p><img src="../img/bulb.png" height="30px" width="auto" style="margin: 0; border: none"/> 推荐用 <code>std::ios::binary</code> 选项打开二进制文件,否则字符串中出现 <code>'\n'</code> 时,会被 MSVC 标准库自动转换成 <code>'\r\n'</code> 来写入,妨碍我们跨平台。</p>
11931252
</blockquote>
1194-
<h2 id="_9">逐行读取文本文件</h2>
1253+
<h2 id="_10">逐行读取文本文件</h2>
11951254
<pre><code class="language-cpp">std::ifstream fin(&quot;test.txt&quot;);
11961255
std::string line;
11971256
while (std::getline(fin, line)) {
11981257
std::cout &lt;&lt; &quot;读取到一行:&quot; &lt;&lt; line &lt;&lt; '\n';
11991258
}
12001259
</code></pre>
1201-
<h2 id="_10">字符串切片</h2>
1260+
<h2 id="_11">字符串切片</h2>
12021261
<pre><code class="language-cpp">#include &lt;sstream&gt;
12031262
#include &lt;string&gt;
12041263
#include &lt;vector&gt;
@@ -1341,7 +1400,7 @@ <h2 id="cerr-cout">cerr 与 cout 的抉择</h2>
13411400
1 3 5 7
13421401
11 13 17 19
13431402
</code></pre>
1344-
<h2 id="_11">智能指针防止大对象移动</h2>
1403+
<h2 id="_12">智能指针防止大对象移动</h2>
13451404
<p>我们说一个类型大,有两种情况。</p>
13461405
<ol>
13471406
<li>类本身很大:例如 array</li>
@@ -1619,7 +1678,7 @@ <h3 id="thread">thread 膝盖中箭</h3>
16191678
t.join();
16201679
printf(&quot;%d\n&quot;, x); // 42
16211680
</code></pre>
1622-
<h3 id="_12">举个绑定随机数生成器例子</h3>
1681+
<h3 id="_13">举个绑定随机数生成器例子</h3>
16231682
<p>bind 写法:</p>
16241683
<pre><code class="language-cpp">std::mt19937 gen(seed);
16251684
std::uniform_real_distribution&lt;double&gt; uni(0, 1);
@@ -1831,7 +1890,7 @@ <h2 id="bind-lambda-bind_front">bind 绑定成员函数是陋习,改用 lambda
18311890
auto memfn = BIND(world, this); // 小彭老师的 BIND 宏,C++14 起可用
18321891
</code></pre>
18331892
<p>你更喜欢哪一种呢?</p>
1834-
<h2 id="_13">救命!为什么我的全局函数不能作为函数对象?</h2>
1893+
<h2 id="_14">救命!为什么我的全局函数不能作为函数对象?</h2>
18351894
<p>当你的全局函数是模板函数,或带有重载的函数时:</p>
18361895
<pre><code class="language-cpp">template &lt;class T&gt;
18371896
T square(T const t) {
@@ -1903,14 +1962,14 @@ <h2 id="map-any">map + any 外挂属性</h2>
19031962
<p>TODO</p>
19041963
<h2 id="shared_ptr-deleter">自定义 shared_ptr 的 deleter</h2>
19051964
<h2 id="check_cuda">CHECK_CUDA 类错误检测宏</h2>
1906-
<h2 id="_14">函数默认参数求值的位置是调用者</h2>
1965+
<h2 id="_15">函数默认参数求值的位置是调用者</h2>
19071966
<h2 id="locale-utf8">设置 locale 为 .utf8</h2>
1908-
<h2 id="_15">花括号实现安全的类型转换检查</h2>
1967+
<h2 id="_16">花括号实现安全的类型转换检查</h2>
19091968
<h2 id="this">成员函数针对 this 的移动重载</h2>
19101969
<h2 id="check_cuda_1">CHECK_CUDA 类错误检测宏</h2>
1911-
<h2 id="_16">函数默认参数求值的位置是调用者</h2>
1912-
<h2 id="_17">花括号实现安全的类型转换检查</h2>
1913-
<h2 id="_18">临时右值转左值</h2>
1970+
<h2 id="_17">函数默认参数求值的位置是调用者</h2>
1971+
<h2 id="_18">花括号实现安全的类型转换检查</h2>
1972+
<h2 id="_19">临时右值转左值</h2>
19141973
<p>C++ 有个特性:支持纯右值(prvalue)隐式转换成 const 的左值引用。</p>
19151974
<p>翻译:<code>int &amp;&amp;</code> 可以自动转换成 <code>int const &amp;</code></p>
19161975
<pre><code class="language-cpp">void func(int const &amp;i);
@@ -1995,7 +2054,7 @@ <h2 id="bit-field">位域(bit-field)</h2>
19952054
</code></pre>
19962055
<h2 id="vector-unordered_map-lru-cache">vector + unordered_map = LRU cache</h2>
19972056
<h2 id="lambda-unique_ptr-function">Lambda 捕获 unique_ptr 导致 function 报错怎么办</h2>
1998-
<h2 id="_19">多线程通信应基于队列,而不是共享全局变量</h2>
2057+
<h2 id="_20">多线程通信应基于队列,而不是共享全局变量</h2>
19992058
<h2 id="raii-finally">RAII 的 finally 帮手类</h2>
20002059
<h2 id="swap-mutex">swap 缩小 mutex 区间代价</h2>
20012060
<h2 id="namespace">namespace 别名</h2></div>

index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ <h2 id="_1">前言</h2>
292292
<blockquote>
293293
<p><img src="./img/bulb.png" height="30px" width="auto" style="margin: 0; border: none"/> 本书还在持续更新中……要追番的话,可以在 <a href="https://github.com/parallel101/cppguidebook">GitHub</a> 点一下右上角的 “Watch” 按钮,每当小彭老师提交新 commit,GitHub 会向你发送一封电子邮件,提醒你小彭老师更新了。</p>
294294
</blockquote>
295-
<p>更新时间:2024年10月18日 15:48:05 (UTC+08:00)</p>
295+
<p>更新时间:2024年10月25日 12:47:54 (UTC+08:00)</p>
296296
<p><a href="https://parallel101.github.io/cppguidebook">在 GitHub Pages 浏览本书</a> | <a href="https://142857.red/book">在小彭老师自己维护的镜像上浏览本书</a></p>
297297
<h2 id="_2">格式约定</h2>
298298
<blockquote>

0 commit comments

Comments
 (0)