-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlocal-search.xml
923 lines (443 loc) · 374 KB
/
local-search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>C++ mutex</title>
<link href="/cpp/mutex/"/>
<url>/cpp/mutex/</url>
<content type="html"><![CDATA[<!--- [std::mutex](#stdmutex)- [std::recursive_mutex](#stdrecursive_mutex)- [std::time_mutex](#stdtime_mutex)- [std::recursive_timed\_mutex](#stdrecursive_timed_mutex)- [std::shared_mutex](#stdshared_mutex)- [std::lock_guard](#stdlock_guard)- [std::unique_lock](#stdunique_lock)- [std::shared_lock](#stdshared_lock)- [std::scoped_lock](#stdscoped_lock)- [std::lock](#stdlock)- [Reference](#reference)--><h2 id="std-mutex"><a href="#std-mutex" class="headerlink" title="std::mutex"></a>std::mutex</h2><p><a href="https://en.cppreference.com/w/cpp/thread/mutex">Since C++ 11</a></p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><mutex></span></span><br></code></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-built_in">mutex</span>(<span class="hljs-type">const</span> mutex&) = <span class="hljs-keyword">delete</span>; <span class="hljs-comment">// copy constructor</span><br>mutex& <span class="hljs-keyword">operator</span>=(<span class="hljs-type">const</span> mutex&) = <span class="hljs-keyword">delete</span>; <span class="hljs-comment">// copy operator</span><br></code></pre></td></tr></table></figure><p>最基本的互斥锁。默认 unlocked。不可拷贝、赋值、移动。</p><p><code>lock</code>:调用线程将锁住该互斥量;如果互斥量被其他线程占有,则当前线程会被阻塞;当前线程在未解锁的情况下重复<code>lock</code>会产生死锁(deadlock)<br><code>try_lock</code>:尝试锁住互斥量;如果互斥量被其他线程占有,则当前线程也不会被阻塞,函数返回 false;当前线程在未解锁的情况下重复<code>try_lock</code>会产生死锁(deadlock)<br><code>unlock</code>:解锁</p><h2 id="std-recursive-mutex"><a href="#std-recursive-mutex" class="headerlink" title="std::recursive_mutex"></a>std::recursive_mutex</h2><p><a href="https://en.cppreference.com/w/cpp/thread/recursive_mutex">Since C++ 11</a></p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><mutex></span></span><br></code></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-built_in">recursive_mutex</span>(<span class="hljs-type">const</span> recursive_mutex&) = <span class="hljs-keyword">delete</span>;<br>recursive_mutex& <span class="hljs-keyword">operator</span>=(<span class="hljs-type">const</span> recursive_mutex&) = <span class="hljs-keyword">delete</span>;<br></code></pre></td></tr></table></figure><p>递归互斥锁,允许多次上锁,解锁时也需要多次解锁,即<code>lock</code>与<code>unlock</code>次数相同。</p><p>首次加锁的线程可以多次加锁,其它线程会阻塞;解锁时也需要多次解锁。可解决同一个线程死锁的问题。</p><p>其它特性与 <a href="#std-mutex">std::mutex</a> 类似。</p><h2 id="std-time-mutex"><a href="#std-time-mutex" class="headerlink" title="std::time_mutex"></a>std::time_mutex</h2><p><a href="https://en.cppreference.com/w/cpp/thread/time_mutex">Since C++ 11</a></p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><mutex></span></span><br></code></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-built_in">timed_mutex</span>(<span class="hljs-type">const</span> timed_mutex&) = <span class="hljs-keyword">delete</span>;<br>timed_mutex& <span class="hljs-keyword">operator</span>=(<span class="hljs-type">const</span> timed_mutex&) = <span class="hljs-keyword">delete</span>;<br></code></pre></td></tr></table></figure><p><code>try_lock_for</code>函数接受一个时间范围作为参数,在时间范围内线程如果没有获得锁则被阻塞住,如果在此期间其他线程释放了锁,则该线程可以获得互斥锁,如果超时,则返回 false。<br><code>try_lock_until</code>函数接受一个时间点作为参数,在指定时间点到来之前线程如果没有获得锁则被阻塞住,如果在此期间其他线程释放了锁,则该线程可以获得互斥锁,如果超时,则返回 false。</p><p>其它特性与 <a href="#std-mutex">std::mutex</a> 类似。</p><h2 id="std-recursive-timed-mutex"><a href="#std-recursive-timed-mutex" class="headerlink" title="std::recursive_timed_mutex"></a>std::recursive_timed_mutex</h2><p><a href="https://en.cppreference.com/w/cpp/thread/recursive_timed_mutex">Since C++ 11</a></p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><mutex></span></span><br></code></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-built_in">recursive_timed_mutex</span>(<span class="hljs-type">const</span> recursive_timed_mutex&) = <span class="hljs-keyword">delete</span>;<br>recursive_timed_mutex& <span class="hljs-keyword">operator</span>=(<span class="hljs-type">const</span> recursive_timed_mutex&) = <span class="hljs-keyword">delete</span>;<br></code></pre></td></tr></table></figure><p>结合 <a href="#std-recursive_mutex">std::recursive_mutex</a> 和 <a href="#std-time_mutex">std::time_mutex</a> 特性。</p><h2 id="std-shared-mutex"><a href="#std-shared-mutex" class="headerlink" title="std::shared_mutex"></a>std::shared_mutex</h2><p><a href="https://en.cppreference.com/w/cpp/thread/shared_mutex">Since C++ 17</a></p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><shared_mutex></span></span><br></code></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-built_in">shared_mutex</span>(<span class="hljs-type">const</span> shared_mutex&) = <span class="hljs-keyword">delete</span>;<br>shared_mutex& <span class="hljs-keyword">operator</span>=(<span class="hljs-type">const</span> shared_mutex&) = <span class="hljs-keyword">delete</span>;<br><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">lock</span><span class="hljs-params">()</span> <span class="hljs-keyword">noexcept</span></span>;<br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">try_lock</span><span class="hljs-params">()</span> <span class="hljs-keyword">noexcept</span></span>;<br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">unlock</span><span class="hljs-params">()</span> <span class="hljs-keyword">noexcept</span></span>;<br><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">lock_shared</span><span class="hljs-params">()</span> <span class="hljs-keyword">noexcept</span></span>;<br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">try_lock_shared</span><span class="hljs-params">()</span> <span class="hljs-keyword">noexcept</span></span>;<br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">unlock_shared</span><span class="hljs-params">()</span> <span class="hljs-keyword">noexcept</span></span>;<br></code></pre></td></tr></table></figure><p>写线程以独占模式持有锁,读取线程可以同时持有锁。</p><p>写线程持有锁,其它读、写线程均阻塞等待;<br>读线程持有锁,其它读线程可以同时持有锁,写线程阻塞等待。</p><h2 id="std-lock-guard"><a href="#std-lock-guard" class="headerlink" title="std::lock_guard"></a>std::lock_guard</h2><p><a href="https://en.cppreference.com/w/cpp/thread/lock_guard">Since C++ 11</a></p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><mutex></span></span><br></code></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-built_in">lock_guard</span>(<span class="hljs-type">const</span> lock_guard&) = <span class="hljs-keyword">delete</span>;<br>lock_guard& <span class="hljs-keyword">operator</span>=(<span class="hljs-type">const</span> lock_guard&) = <span class="hljs-keyword">delete</span>;<br></code></pre></td></tr></table></figure><p>不支持主动解锁,需要等析构时自动解锁。</p><h2 id="std-unique-lock"><a href="#std-unique-lock" class="headerlink" title="std::unique_lock"></a>std::unique_lock</h2><p><a href="https://en.cppreference.com/w/cpp/thread/unique_lock">Since C++ 11</a></p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><mutex></span></span><br></code></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-built_in">unique_lock</span>() <span class="hljs-keyword">noexcept</span> = <span class="hljs-keyword">default</span>;<br><br><span class="hljs-built_in">unique_lock</span>(_Mutex& _Mtx); <span class="hljs-comment">// construct and lock</span><br><span class="hljs-built_in">unique_lock</span>(_Mutex& _Mtx, <span class="hljs-type">adopt_lock_t</span>) <span class="hljs-keyword">noexcept</span>; <span class="hljs-comment">// construct and assume already locked</span><br><span class="hljs-built_in">unique_lock</span>(_Mutex& _Mtx, <span class="hljs-type">defer_lock_t</span>) <span class="hljs-keyword">noexcept</span>; <span class="hljs-comment">// construct but don't lock</span><br><span class="hljs-built_in">unique_lock</span>(_Mutex& _Mtx, <span class="hljs-type">try_to_lock_t</span>); <span class="hljs-comment">// construct and try to lock (try_lock)</span><br><span class="hljs-built_in">unique_lock</span>(_Mutex& _Mtx, <span class="hljs-type">const</span> chrono::duration<_Rep, _Period>& _Rel_time); <span class="hljs-comment">// construct and lock with timeout (try_lock_for)</span><br><span class="hljs-built_in">unique_lock</span>(_Mutex& _Mtx, <span class="hljs-type">const</span> chrono::time_point<_Clock, _Duration>& _Abs_time); <span class="hljs-comment">// construct and lock with timeout (try_lock_until)</span><br><br><span class="hljs-built_in">unique_lock</span>(unique_lock&& _Other) <span class="hljs-keyword">noexcept</span>; <span class="hljs-comment">// move constructor</span><br>unique_lock& <span class="hljs-keyword">operator</span>=(unique_lock&& _Other) <span class="hljs-keyword">noexcept</span>; <span class="hljs-comment">// move operator</span><br><br><span class="hljs-built_in">unique_lock</span>(<span class="hljs-type">const</span> unique_lock&) = <span class="hljs-keyword">delete</span>; <span class="hljs-comment">// copy constructor</span><br>unique_lock& <span class="hljs-keyword">operator</span>=(<span class="hljs-type">const</span> unique_lock&) = <span class="hljs-keyword">delete</span>; <span class="hljs-comment">// copy operator</span><br><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">lock</span><span class="hljs-params">()</span></span>;<br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">try_lock</span><span class="hljs-params">()</span></span>;<br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">unlock</span><span class="hljs-params">()</span></span>;<br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">try_lock_for</span><span class="hljs-params">(<span class="hljs-type">const</span> chrono::duration<_Rep, _Period>& _Rel_time)</span></span>;<br><span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">try_lock_until</span><span class="hljs-params">(<span class="hljs-type">const</span> chrono::time_point<_Clock, _Duration>& _Abs_time)</span></span>;<br></code></pre></td></tr></table></figure><p>支持主动解锁;不可拷贝、赋值;可移动;不锁定、超时锁。</p><p>通过构造函数可以看出,<code>unique_lock</code>与不同类型的<code>mutex</code>搭配使用,会产生不同的特性。<br>与<code>shared_mutex</code>搭配使用,对象构造时自动对<code>shared_mutex</code>加写锁,析构时自动解写锁。写独占。</p><h2 id="std-shared-lock"><a href="#std-shared-lock" class="headerlink" title="std::shared_lock"></a>std::shared_lock</h2><p><a href="https://en.cppreference.com/w/cpp/thread/shared_lock">Since C++ 14</a></p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><shared_mutex></span></span><br></code></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-built_in">shared_lock</span>(<span class="hljs-type">const</span> shared_lock&) = <span class="hljs-keyword">delete</span>;<br>shared_lock& <span class="hljs-keyword">operator</span>=(<span class="hljs-type">const</span> shared_lock&) = <span class="hljs-keyword">delete</span>;<br></code></pre></td></tr></table></figure><p>与<code>shared_mutex</code>配合使用,对象构造时自动对<code>shared_mutex</code>加读锁,析构时自动对<code>shared_mutex</code>解读锁。读共享。</p><h2 id="std-scoped-lock"><a href="#std-scoped-lock" class="headerlink" title="std::scoped_lock"></a>std::scoped_lock</h2><p><a href="https://en.cppreference.com/w/cpp/thread/scoped_lock">Since C++ 17</a></p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><mutex></span></span><br></code></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-built_in">scoped_lock</span>(_Mutexes&... _Mtxes); <span class="hljs-comment">// construct and lock</span><br><span class="hljs-built_in">scoped_lock</span>(<span class="hljs-type">adopt_lock_t</span>, _Mutexes&... _Mtxes) <span class="hljs-keyword">noexcept</span>; <span class="hljs-comment">// construct but don't lock</span><br><br><span class="hljs-built_in">scoped_lock</span>(<span class="hljs-type">const</span> scoped_lock&) = <span class="hljs-keyword">delete</span>;<br>scoped_lock& <span class="hljs-keyword">operator</span>=(<span class="hljs-type">const</span> scoped_lock&) = <span class="hljs-keyword">delete</span>;<br></code></pre></td></tr></table></figure><h2 id="std-lock"><a href="#std-lock" class="headerlink" title="std::lock"></a>std::lock</h2><p><a href="https://en.cppreference.com/w/cpp/thread/lock">Since C++ 11</a></p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><mutex></span></span><br></code></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs cpp">std::mutex mtx1, mtx2;<br>std::<span class="hljs-built_in">lock</span>(mtx1, mtx2);<br></code></pre></td></tr></table></figure><p>用算法避免死锁。</p><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><ul><li><a href="https://blog.csdn.net/sinat_31608641/article/details/107733436">C++ mutex 的使用</a></li><li><a href="https://www.cnblogs.com/haippy/p/3237213.html">C++11 并发指南三(std::mutex 详解)</a></li><li><a href="https://blog.csdn.net/wangzhicheng1983/article/details/119481595">c++17 区域锁 std::scoped_lock 应用实例</a></li><li><a href="https://blog.csdn.net/whl0071/article/details/126464767">C++ 多线程:锁管理(lock)</a></li><li><a href="https://dengzuoheng.github.io/cpp-concurency-pattern-7-rwlock">C++ 并发型模式#7: 读写锁 - shared_mutex</a></li></ul>]]></content>
<categories>
<category>cpp</category>
</categories>
<tags>
<tag>CPP</tag>
</tags>
</entry>
<entry>
<title>Prototype Pattern</title>
<link href="/design-pattern/prototype/"/>
<url>/design-pattern/prototype/</url>
<content type="html"><![CDATA[<p>简化对象的创建过程。</p><p><img src="/design-pattern/prototype/images/prototype.svg" alt="Prototype Pattern"></p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-comment">// prototype</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Animal</span><br>{<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-built_in">Animal</span>() = <span class="hljs-keyword">default</span>;<br> <span class="hljs-keyword">virtual</span> ~<span class="hljs-built_in">Animal</span>() = <span class="hljs-keyword">default</span>;<br><br> <span class="hljs-function"><span class="hljs-keyword">virtual</span> Animal *<span class="hljs-title">clone</span><span class="hljs-params">()</span> </span>= <span class="hljs-number">0</span>;<br> <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">play</span><span class="hljs-params">()</span> </span>= <span class="hljs-number">0</span>;<br>};<br></code></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-comment">// concrete prototype</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Dog</span> : <span class="hljs-keyword">public</span> Animal<br>{<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-built_in">Dog</span>() {}<br> ~<span class="hljs-built_in">Dog</span>() <span class="hljs-keyword">override</span> {}<br><br> <span class="hljs-function">Animal *<span class="hljs-title">clone</span><span class="hljs-params">()</span> <span class="hljs-keyword">override</span></span><br><span class="hljs-function"> </span>{<br> Dog *dog = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Dog</span>(); <span class="hljs-comment">// 创建对象</span><br> <span class="hljs-built_in">strncpy</span>(dog->m_name, m_name, <span class="hljs-number">32</span>); <span class="hljs-comment">// 深拷贝成员变量</span><br> <span class="hljs-keyword">return</span> dog;<br> }<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">play</span><span class="hljs-params">()</span> <span class="hljs-keyword">override</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-comment">// play</span><br> }<br><br><span class="hljs-keyword">private</span>:<br> <span class="hljs-type">char</span> m_name[<span class="hljs-number">32</span>];<br>};<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Cat</span> : <span class="hljs-keyword">public</span> Animal<br>{<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-built_in">Cat</span>() {}<br> ~<span class="hljs-built_in">Cat</span>() <span class="hljs-keyword">override</span> {}<br><br> <span class="hljs-function">Animal *<span class="hljs-title">clone</span><span class="hljs-params">()</span> <span class="hljs-keyword">override</span></span><br><span class="hljs-function"> </span>{<br> Cat *cat = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Cat</span>();<br> <span class="hljs-built_in">strncpy</span>(cat->m_name, m_name, <span class="hljs-number">32</span>);<br> <span class="hljs-keyword">return</span> cat;<br> }<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">play</span><span class="hljs-params">()</span> <span class="hljs-keyword">override</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-comment">// play</span><br> }<br><br><span class="hljs-keyword">private</span>:<br> <span class="hljs-type">char</span> m_name[<span class="hljs-number">32</span>];<br>};<br></code></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">"animal.h"</span></span><br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-type">int</span> argc, <span class="hljs-type">char</span> *argv[])</span></span><br><span class="hljs-function"></span>{<br> Dog *dog = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Dog</span>();<br> Cat *cat = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Cat</span>();<br><br> Animal *animal1 = dog-><span class="hljs-built_in">clone</span>();<br> Animal *animal2 = cat-><span class="hljs-built_in">clone</span>();<br><br> animal1-><span class="hljs-built_in">play</span>();<br> animal2-><span class="hljs-built_in">play</span>();<br><br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><ul><li><a href="https://blog.csdn.net/jj6666djdbbd/article/details/128621283">C++设计模式:原型模式(详解+实现案例)</a></li></ul>]]></content>
<categories>
<category>design pattern</category>
</categories>
<tags>
<tag>CPP</tag>
<tag>DesignPattern</tag>
</tags>
</entry>
<entry>
<title>Mediator Pattern</title>
<link href="/design-pattern/mediator/"/>
<url>/design-pattern/mediator/</url>
<content type="html"><![CDATA[<p>聊天服务器与用户之间的关系,一个用户向另一个用户发送的消息由聊天服务器执行,用户不关注发送细节。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-comment">// Mediator</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">User</span>;<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Mediator</span><br>{<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-built_in">Mediator</span>() = <span class="hljs-keyword">default</span>;<br> <span class="hljs-keyword">virtual</span> ~<span class="hljs-built_in">Mediator</span>() = <span class="hljs-keyword">default</span>;<br><br> <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">registerUser</span><span class="hljs-params">(User *user)</span> </span>= <span class="hljs-number">0</span>;<br> <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">unregisterUser</span><span class="hljs-params">(User *user)</span> </span>= <span class="hljs-number">0</span>;<br> <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">bool</span> <span class="hljs-title">relayMsg</span><span class="hljs-params">(<span class="hljs-type">const</span> std::string &from, <span class="hljs-type">const</span> std::string &to, <span class="hljs-type">const</span> std::string &msg)</span> </span>= <span class="hljs-number">0</span>;<br>};<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">ChatService</span> : <span class="hljs-keyword">public</span> Mediator<br>{<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-built_in">ChatService</span>();<br> ~<span class="hljs-built_in">ChatService</span>() <span class="hljs-keyword">override</span>;<br><br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">registerUser</span><span class="hljs-params">(User *user)</span> <span class="hljs-keyword">override</span> </span>{ m_users.<span class="hljs-built_in">emplace_back</span>(user); }<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">unregisterUser</span><span class="hljs-params">(User *user)</span> <span class="hljs-keyword">override</span> </span>{ m_users.<span class="hljs-built_in">remove</span>(user); }<br> <span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">relayMsg</span><span class="hljs-params">(<span class="hljs-type">const</span> std::string &from, <span class="hljs-type">const</span> std::string &to, <span class="hljs-type">const</span> std::string &msg)</span> <span class="hljs-keyword">override</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-keyword">for</span> (User *user : m_users) {<br> <span class="hljs-keyword">if</span> (user-><span class="hljs-built_in">id</span>() != to) {<br> <span class="hljs-keyword">continue</span>;<br> }<br> user-><span class="hljs-built_in">recv</span>(from, msg);<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br> }<br><br><span class="hljs-keyword">protected</span>:<br> std::list<User *> m_users;<br>};<br></code></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-comment">// User</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Mediator</span>;<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">User</span><br>{<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-built_in">User</span>() = <span class="hljs-keyword">default</span>;<br> <span class="hljs-keyword">virtual</span> ~<span class="hljs-built_in">User</span>() = <span class="hljs-keyword">default</span>;<br><br> <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">const</span> std::string &<span class="hljs-title">id</span><span class="hljs-params">()</span> <span class="hljs-type">const</span> </span>= <span class="hljs-number">0</span>;<br> <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">bool</span> <span class="hljs-title">send</span><span class="hljs-params">(<span class="hljs-type">const</span> std::string &to, <span class="hljs-type">const</span> std::string &msg)</span> </span>= <span class="hljs-number">0</span>;<br> <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">recv</span><span class="hljs-params">(<span class="hljs-type">const</span> std::string &from, <span class="hljs-type">const</span> std::string &msg)</span> </span>= <span class="hljs-number">0</span>;<br>};<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">GeneralUser</span> : <span class="hljs-keyword">public</span> User<br>{<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-function"><span class="hljs-keyword">explicit</span> <span class="hljs-title">GeneralUser</span><span class="hljs-params">(<span class="hljs-type">const</span> std::string &id, Mediator *mediator = <span class="hljs-literal">nullptr</span>)</span></span>;<br> ~<span class="hljs-built_in">GeneralUser</span>() <span class="hljs-keyword">override</span>;<br><br> <span class="hljs-function"><span class="hljs-type">const</span> std::string &<span class="hljs-title">id</span><span class="hljs-params">()</span> <span class="hljs-type">const</span> <span class="hljs-keyword">override</span> </span>{ <span class="hljs-keyword">return</span> m_id; }<br> <span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">send</span><span class="hljs-params">(<span class="hljs-type">const</span> std::string &to, <span class="hljs-type">const</span> std::string &msg)</span> <span class="hljs-keyword">override</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-keyword">if</span> (m_mediator == <span class="hljs-literal">nullptr</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br> }<br> <span class="hljs-keyword">return</span> m_mediator-><span class="hljs-built_in">relayMsg</span>(m_id, to, msg);<br> }<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">recv</span><span class="hljs-params">(<span class="hljs-type">const</span> std::string &from, <span class="hljs-type">const</span> std::string &msg)</span> <span class="hljs-keyword">override</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-comment">// recived a message</span><br> }<br><br><span class="hljs-keyword">protected</span>:<br> Mediator *m_mediator;<br> std::string m_id;<br>};<br></code></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-comment">// main</span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">"mediator.h"</span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">"user.h"</span></span><br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-type">int</span> argc, <span class="hljs-type">char</span> *argv[])</span></span><br><span class="hljs-function"></span>{<br> ChatService chatService;<br> <span class="hljs-function">GeneralUser <span class="hljs-title">userA</span><span class="hljs-params">(<span class="hljs-string">"13579"</span>, &chatService)</span></span>;<br> <span class="hljs-function">GeneralUser <span class="hljs-title">userB</span><span class="hljs-params">(<span class="hljs-string">"02468"</span>, &chatService)</span></span>;<br> <span class="hljs-function">GeneralUser <span class="hljs-title">userC</span><span class="hljs-params">(<span class="hljs-string">"12345"</span>, &chatService)</span></span>;<br><br> chatService.<span class="hljs-built_in">registerUser</span>(&userA);<br> chatService.<span class="hljs-built_in">registerUser</span>(&userB);<br> chatService.<span class="hljs-built_in">registerUser</span>(&userC);<br><br> userA.<span class="hljs-built_in">send</span>(<span class="hljs-string">"02468"</span>, <span class="hljs-string">"Hello, 02468!"</span>);<br> userA.<span class="hljs-built_in">send</span>(<span class="hljs-string">"12345"</span>, <span class="hljs-string">"Hello, 12345!"</span>);<br><br> userB.<span class="hljs-built_in">send</span>(<span class="hljs-string">"13579"</span>, <span class="hljs-string">"Hello, 13579!"</span>);<br> userB.<span class="hljs-built_in">send</span>(<span class="hljs-string">"12345"</span>, <span class="hljs-string">"Hello, 12345!"</span>);<br><br> userC.<span class="hljs-built_in">send</span>(<span class="hljs-string">"13579"</span>, <span class="hljs-string">"Hello, 13579!"</span>);<br> userC.<span class="hljs-built_in">send</span>(<span class="hljs-string">"02468"</span>, <span class="hljs-string">"Hello, 02468!"</span>);<br><br> chatService.<span class="hljs-built_in">unregisterUser</span>(&userC);<br><br> userA.<span class="hljs-built_in">send</span>(<span class="hljs-string">"02468"</span>, <span class="hljs-string">"Hello, 02468!"</span>);<br> userA.<span class="hljs-built_in">send</span>(<span class="hljs-string">"12345"</span>, <span class="hljs-string">"Hello, 12345!"</span>);<br><br> userB.<span class="hljs-built_in">send</span>(<span class="hljs-string">"13579"</span>, <span class="hljs-string">"Hello, 13579!"</span>);<br> userB.<span class="hljs-built_in">send</span>(<span class="hljs-string">"12345"</span>, <span class="hljs-string">"Hello, 12345!"</span>);<br><br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><ul><li><a href="https://www.runoob.com/design-pattern/mediator-pattern.html">中介者模式</a></li></ul>]]></content>
<categories>
<category>design pattern</category>
</categories>
<tags>
<tag>CPP</tag>
<tag>DesignPattern</tag>
</tags>
</entry>
<entry>
<title>Observer Pattern</title>
<link href="/design-pattern/observer/"/>
<url>/design-pattern/observer/</url>
<content type="html"><![CDATA[<p>公众号与订阅者之间的关系,一对多。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-comment">// Observer</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Observer</span><br>{<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-built_in">Observer</span>() = <span class="hljs-keyword">default</span>;<br> <span class="hljs-keyword">virtual</span> ~<span class="hljs-built_in">Observer</span>() = <span class="hljs-keyword">default</span>;<br><br> <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">update</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">char</span> *msg)</span> </span>= <span class="hljs-number">0</span>;<br>};<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Subscriber</span> : <span class="hljs-keyword">public</span> Observer<br>{<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-function"><span class="hljs-keyword">explicit</span> <span class="hljs-title">Subscriber</span><span class="hljs-params">(<span class="hljs-type">const</span> std::string &id)</span> </span>{}<br> ~<span class="hljs-built_in">Subscriber</span>() <span class="hljs-keyword">override</span> {}<br><br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">update</span><span class="hljs-params">(<span class="hljs-type">const</span> std::string &msg)</span> <span class="hljs-keyword">override</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-comment">// recived a new message</span><br> }<br><br><span class="hljs-keyword">private</span>:<br> std::string m_id;<br>};<br></code></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-comment">// Subject</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Observer</span>;<br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Subject</span><br>{<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-built_in">Subject</span>() = <span class="hljs-keyword">default</span>;<br> <span class="hljs-keyword">virtual</span> ~<span class="hljs-built_in">Subject</span>() = <span class="hljs-keyword">default</span>;<br><br> <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">notify</span><span class="hljs-params">()</span> </span>= <span class="hljs-number">0</span>;<br> <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">registerObserver</span><span class="hljs-params">(Observer *)</span> </span>= <span class="hljs-number">0</span>;<br> <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">unregisterObserver</span><span class="hljs-params">(Observer *)</span> </span>= <span class="hljs-number">0</span>;<br>};<br><span class="hljs-keyword">class</span> <span class="hljs-title class_">Service</span> : <span class="hljs-keyword">public</span> Subject<br>{<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-built_in">Service</span>() {}<br> ~<span class="hljs-built_in">Service</span>() <span class="hljs-keyword">override</span> {}<br><br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">notify</span><span class="hljs-params">()</span> <span class="hljs-keyword">override</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-keyword">for</span> (Observer *obs : m_observers) {<br> obs-><span class="hljs-built_in">update</span>(<span class="hljs-string">"Hello!"</span>);<br> }<br> }<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">registerObserver</span><span class="hljs-params">(Observer *observer)</span> <span class="hljs-keyword">override</span></span><br><span class="hljs-function"> </span>{<br> m_observers.<span class="hljs-built_in">emplace_back</span>(observer);<br> observer-><span class="hljs-built_in">update</span>(<span class="hljs-string">"Subscribe successfully!"</span>);<br> }<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">unregisterObserver</span><span class="hljs-params">(Observer *observer)</span> <span class="hljs-keyword">override</span></span>;<br> {<br> m_observers.<span class="hljs-built_in">remove</span>(observer);<br> observer-><span class="hljs-built_in">update</span>(<span class="hljs-string">"Unsubscribe successfully!"</span>);<br> }<br><br><span class="hljs-keyword">protected</span>:<br> std::list<Observer *> m_observers;<br>};<br></code></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-comment">// main</span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">"observer.h"</span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">"subject.h"</span></span><br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-type">int</span> argc, <span class="hljs-type">char</span> *argv[])</span></span><br><span class="hljs-function"></span>{<br> Service service;<br> <span class="hljs-function">Subscriber <span class="hljs-title">subscriberA</span><span class="hljs-params">(<span class="hljs-string">"Subscriber A"</span>)</span></span>;<br> <span class="hljs-function">Subscriber <span class="hljs-title">subscriberB</span><span class="hljs-params">(<span class="hljs-string">"Subscriber B"</span>)</span></span>;<br> <span class="hljs-function">Subscriber <span class="hljs-title">subscriberC</span><span class="hljs-params">(<span class="hljs-string">"Subscriber C"</span>)</span></span>;<br><br> service.<span class="hljs-built_in">registerObserver</span>(&subscriberA);<br> service.<span class="hljs-built_in">registerObserver</span>(&subscriberB);<br> service.<span class="hljs-built_in">registerObserver</span>(&subscriberC);<br> service.<span class="hljs-built_in">notify</span>();<br><br> service.<span class="hljs-built_in">unregisterObserver</span>(&subscriberC);<br> service.<span class="hljs-built_in">notify</span>();<br><br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><ul><li><a href="https://www.runoob.com/design-pattern/observer-pattern.html">观察者模式</a></li></ul>]]></content>
<categories>
<category>design pattern</category>
</categories>
<tags>
<tag>CPP</tag>
<tag>DesignPattern</tag>
</tags>
</entry>
<entry>
<title>Google Performance Tools</title>
<link href="/tools/gperftools/"/>
<url>/tools/gperftools/</url>
<content type="html"><![CDATA[<h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo apt install google-perftools libgoogle-perftools-dev<br></code></pre></td></tr></table></figure><h2 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h2><p><code>#include <gperftools/profiler.h></code><br><code>-lprofiler</code></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><gperftools/profiler.h></span></span><br><br><span class="hljs-type">int</span> <span class="hljs-title function_">fun</span><span class="hljs-params">()</span><br>{<br> ProfilerStart(<span class="hljs-string">"xxx.prof"</span>);<br> <span class="hljs-comment">// code</span><br> ProfilerStop();<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 分析结果</span><br>google-pprof --pdf xxx xxx.prof > xxx.pdf<br>google-pprof --gif xxx xxx.prof > xxx.gif<br>google-pprof --text xxx xxx.prof > xxx.text<br></code></pre></td></tr></table></figure><h2 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h2><ol><li><p>程序运行输出<code>PROFILE: interrupts/evictions/bytes = 0/0/64</code><br>这种情况可能是程序占用 CPU 太低了,导致没有分析出结果,可以写个循环验证试试。</p></li><li><p>执行<code>google-pprof</code>输出如下结果,原因同 1</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># Using local file hotplug.</span><br><span class="hljs-comment"># Using local file test.prof.</span><br><span class="hljs-comment"># No nodes to print</span><br></code></pre></td></tr></table></figure></li></ol><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="https://www.cnblogs.com/gary-guo/p/10607514.html">gperftools 对程序进行分析</a></li><li><a href="https://manpages.debian.org/stretch/google-perftools/google-pprof.1.en.html">debian google-pprof</a></li></ul>]]></content>
<categories>
<category>tools</category>
</categories>
<tags>
<tag>Tool</tag>
</tags>
</entry>
<entry>
<title>PlantUML</title>
<link href="/tools/plantuml/"/>
<url>/tools/plantuml/</url>
<content type="html"><![CDATA[<h2 id="VS-Code-PlantUML-环境配置"><a href="#VS-Code-PlantUML-环境配置" class="headerlink" title="VS Code + PlantUML 环境配置"></a>VS Code + PlantUML 环境配置</h2><ol><li>安装 <a href="http://graphviz.org/">graphviz</a></li><li>安装 <a href="https://www.oracle.com/technetwork/java/javase/downloads/index.html">JDK</a>,配置 JAVA 环境,安装好 JDK 后,记得添加环境变量;</li><li>在 VS Code 中新建以<code>.plantuml</code>为文件名后缀的文件,语法见官网说明文档。</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo apt install graphviz openjdk-11-jdk<br></code></pre></td></tr></table></figure><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><ul><li><a href="https://www.jianshu.com/p/e92a52770832">使用 Sublime + PlantUML 高效地画图</a></li><li><a href="http://plantuml.com/zh/index">官方 PlantUML 说明文档</a></li></ul>]]></content>
<categories>
<category>tools</category>
</categories>
<tags>
<tag>Tool</tag>
</tags>
</entry>
<entry>
<title>Visual Studio Code</title>
<link href="/tools/vscode/"/>
<url>/tools/vscode/</url>
<content type="html"><![CDATA[<!--- [简介](#简介)- [安装配置](#安装配置)- [编译调试](#编译调试)- [使用 SSH 进行远程开发](#使用-ssh-进行远程开发)- [参考文献](#参考文献)--><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p><a href="https://code.visualstudio.com/">https://code.visualstudio.com</a></p><h2 id="安装配置"><a href="#安装配置" class="headerlink" title="安装配置"></a>安装配置</h2><p>通用下载链接:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">https://vscode.cdn.azure.cn/stable/{ID}/vscode-server-linux-x64.tar.gz<br>https://vscode.cdn.azure.cn/stable/{ID}/VSCodeUserSetup-x64-1.65.2.exe<br></code></pre></td></tr></table></figure><p>找到下载链接:<code>ps aux | grep wget</code><br>可以看到:<code>wget --tries=0 --connect-timeout=7 --dns-timeout=7 --show-progress -nv -O vscode-server.tar.gz http://update.code.visualstudio.com/commit:b3318bc0524af3d74034b8bb8a64df0ccf35549a/server-linux-x64/stable</code></p><p>找到真正的下载地址,主要是找到 commit id</p><p><code>wget --tries=0 --connect-timeout=7 --dns-timeout=7 --show-progress -O vscode-server.tar.gz http://update.code.visualstudio.com/commit:b3318bc0524af3d74034b8bb8a64df0ccf35549a/server-linux-x64/stable</code></p><p>URL transformed to HTTPS due to an HSTS policy<br>–2021-11-08 15:57:26– <a href="https://update.code.visualstudio.com/commit:b3318bc0524af3d74034b8bb8a64df0ccf35549a/server-linux-x64/stable">https://update.code.visualstudio.com/commit:b3318bc0524af3d74034b8bb8a64df0ccf35549a/server-linux-x64/stable</a><br>Resolving update.code.visualstudio.com (update.code.visualstudio.com)… 20.43.132.130<br>Connecting to update.code.visualstudio.com (update.code.visualstudio.com)|20.43.132.130|:443… connected.<br>HTTP request sent, awaiting response… 302 Found<br>Location: <a href="https://az764295.vo.msecnd.net/stable/b3318bc0524af3d74034b8bb8a64df0ccf35549a/vscode-server-linux-x64.tar.gz">https://az764295.vo.msecnd.net/stable/b3318bc0524af3d74034b8bb8a64df0ccf35549a/vscode-server-linux-x64.tar.gz</a> [following]<br>–2021-11-08 15:57:26– <a href="https://az764295.vo.msecnd.net/stable/b3318bc0524af3d74034b8bb8a64df0ccf35549a/vscode-server-linux-x64.tar.gz">https://az764295.vo.msecnd.net/stable/b3318bc0524af3d74034b8bb8a64df0ccf35549a/vscode-server-linux-x64.tar.gz</a><br>Resolving az764295.vo.msecnd.net (az764295.vo.msecnd.net)… 117.18.232.200<br>Connecting to az764295.vo.msecnd.net (az764295.vo.msecnd.net)|117.18.232.200|:443… connected.<br>HTTP request sent, awaiting response… 200 OK<br>Length: 53650674 (51M) [application/gzip]<br>Saving to: ‘vscode-server.tar.gz’</p><p>使用 vscode.cdn.azure.cn 取代 az764295.vo.msecnd.net</p><p>将下载的文件放入<code>~/.vscode-server/bin/b3318bc0524af3d74034b8bb8a64df0ccf35549a</code></p><p>解压<code>tar xf vscode-server.tar.gz</code></p><p>移动一级目录到上层<code>mv vscode-server-linux-x64/* .</code></p><ul><li><a href="https://blog.csdn.net/liuck/article/details/121210043">国内镜像快速下载 vscode server</a></li><li><a href="https://blog.csdn.net/sinat_23318385/article/details/126268891">服务器手动安装 vscode server</a></li></ul><h2 id="编译调试"><a href="#编译调试" class="headerlink" title="编译调试"></a>编译调试</h2><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-comment">// settings.json</span><br><span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"cmake.configureEnvironment"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"CMAKE_PREFIX_PATH"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"C:/Qt/6.6.2/msvc2019_64"</span><br> <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"cmake.debugConfig"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"args"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-string">"-i"</span><span class="hljs-punctuation">,</span> <span class="hljs-string">"a"</span><span class="hljs-punctuation">]</span><br> <span class="hljs-punctuation">}</span><br><span class="hljs-punctuation">}</span><br></code></pre></td></tr></table></figure><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-comment">// launch.json</span><br><span class="hljs-punctuation">{</span><br> <span class="hljs-comment">// 使用 IntelliSense 了解相关属性。</span><br> <span class="hljs-comment">// 悬停以查看现有属性的描述。</span><br> <span class="hljs-comment">// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387</span><br> <span class="hljs-attr">"version"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"0.2.0"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"configurations"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><br> <span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"(gdb) Launch"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"type"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"cppdbg"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"request"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"launch"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"program"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"${workspaceFolder}/aaa"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"args"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-string">"-i"</span><span class="hljs-punctuation">,</span> <span class="hljs-string">"a"</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"stopAtEntry"</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"cwd"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"${fileDirname}"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"environment"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"externalConsole"</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"MIMode"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"gdb"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"setupCommands"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><br> <span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"description"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"为 gdb 启用整齐打印"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"text"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"-enable-pretty-printing"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"ignoreFailures"</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span><br> <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span><br> <span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"description"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"将反汇编风格设置为 Intel"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"text"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"-gdb-set disassembly-flavor intel"</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"ignoreFailures"</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span><br> <span class="hljs-punctuation">}</span><br> <span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"sourceFileMap"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"${workspace}/bbb"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"."</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"${workspace}/ccc"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"."</span><br> <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"coreDumpPath"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">""</span><br> <span class="hljs-punctuation">}</span><br> <span class="hljs-punctuation">]</span><br><span class="hljs-punctuation">}</span><br></code></pre></td></tr></table></figure><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-comment">// tasks.json</span><br></code></pre></td></tr></table></figure><h2 id="使用-SSH-进行远程开发"><a href="#使用-SSH-进行远程开发" class="headerlink" title="使用 SSH 进行远程开发"></a>使用 SSH 进行远程开发</h2><p>Visual Studio Code 通过远程开发插件可以将 container,远程计算机或 Windows Linux 子系统(WSL)用作完整的开发环境。</p><p><img src="/tools/vscode/image/47e8ae545f43e8c4d6e05e72db91dcd5.png" alt="arch"></p><p>首先安装插件:</p><p><img src="/tools/vscode/image/7d2e48a337d68d353b3a22915674a257.png" alt="extensions-remote"></p><p>在 VS Code 中,从命令面板(F1)中选择“ Remote-SSH:Connect to Host … ”,在窗口中运行以下命令并适当替换“ user@hostname ”来验证您可以连接到 SSH 主机:</p><p><img src="/tools/vscode/image/af5863e550d02cd10598bcd33fade940.png" alt="Illustration of user@host input box"></p><p>如果 VS Code 无法自动检测到要连接的服务器的类型,就需要手动选择类型:</p><p><img src="/tools/vscode/image/e29a3b79ba302a084379449b8c11f21c.png" alt="Illustration of platform selection"></p><p>选择平台后,它将被存储在 remote.SSH.remotePlatform 属性下的 VSCode 设置中,因此你可以随时更改它。<br>稍后,VS Code 将连接到 SSH 服务器并进行自我设置。VS Code 将使用进度通知显示最新状态,并且可以在 Remote-SSH 输出通道中查看详细的日志。<br>你可以打开远程机器上的任何文件夹或工作区通过“ File > Open… or File > Open Workspace… ”,就像在本地打开一样。</p><p><img src="/tools/vscode/image/9b8eb991e15371852f85c9b0c7dcb821.png" alt="File Open on a remote SSH host"></p><p><img src="/tools/vscode/image/528ba421f378905e123f62914eba5704.png" alt="extensions-cmake"></p><p><img src="/tools/vscode/image/2be64f93e2fb568f6836bec2b4122135.png" alt="status"></p><p>在扩展商店里安装 CMake 插件后,就可以直接通过点击 VSCode 状态栏中的图标编译或者调试工程。</p><h2 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h2><ul><li><a href="https://code.visualstudio.com/docs/cpp/cpp-debug#_windows-debugging-with-gdb">Debug C++ in Visual Studio Code</a></li><li><a href="https://blog.csdn.net/qq_38292379/article/details/126410156">嵌入式如何使用 vscode/gdb/gdbserver 调试程序或 coredump(内存不足以运行 gdb 的情况下)</a></li><li><a href="https://blog.csdn.net/zhengnianli/article/details/117538399">手把手教你使用 VSCode + gdb + gdbserver 调试 ARM 程序</a></li></ul>]]></content>
<categories>
<category>tools</category>
</categories>
<tags>
<tag>Tool</tag>
</tags>
</entry>
<entry>
<title>tar</title>
<link href="/tools/tar/"/>
<url>/tools/tar/</url>
<content type="html"><![CDATA[<h2 id="Overview"><a href="#Overview" class="headerlink" title="Overview"></a>Overview</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">tar --<span class="hljs-built_in">help</span> <span class="hljs-comment"># help</span><br>tar -xzf aaa.tar.gz <span class="hljs-comment"># extract</span><br>tar -czf aaa.tar.gz aaa <span class="hljs-comment"># compress</span><br></code></pre></td></tr></table></figure><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><ul><li><a href="https://www.howtogeek.com/248780/how-to-compress-and-extract-files-using-the-tar-command-on-linux/">How to Compress and Extract Files Using the tar Command on Linux</a></li></ul>]]></content>
<categories>
<category>tools</category>
</categories>
<tags>
<tag>Tool</tag>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title>zip</title>
<link href="/tools/zip/"/>
<url>/tools/zip/</url>
<content type="html"><![CDATA[<h2 id="Overview"><a href="#Overview" class="headerlink" title="Overview"></a>Overview</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo apt install zip unzip<br>sudo yum install zip unzip<br><br>zip aaa bbb <span class="hljs-comment"># compress</span><br>unzip aaa.zip <span class="hljs-comment"># extract</span><br>unzip xxx.zip -d xxx <span class="hljs-comment"># 解压文件到指定目录</span><br>unzip -o xxx.zip -d xxx <span class="hljs-comment"># 覆盖已存在的文件</span><br></code></pre></td></tr></table></figure><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><ul><li><a href="https://phoenixnap.com/kb/how-to-zip-a-file-in-linux">How to Zip a File in Linux</a></li><li><a href="https://iq.direct/blog/49-how-to-unzip-file-on-ubuntu-linux.html">HOW TO UNZIP FILE ON UBUNTU LINUX</a></li></ul>]]></content>
<categories>
<category>tools</category>
</categories>
<tags>
<tag>Tool</tag>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title>lipo</title>
<link href="/macos/lipo/"/>
<url>/macos/lipo/</url>
<content type="html"><![CDATA[<h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 详情</span><br>lipo -info XXXX<br>lipo -archs XXXX<br><span class="hljs-comment"># 拆分</span><br>lipo XXXX.framework/XXXX -thin armv7 -output XXXX_armv7<br>lipo XXXX.framework/XXXX -thin arm64 -output XXXX_arm64<br><span class="hljs-comment"># 合并</span><br>lipo -create XXXX_armv7 XXXX_arm64 -output XXXX<br></code></pre></td></tr></table></figure><h2 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h2><ul><li><a href="https://blog.csdn.net/yepiaouang/article/details/79353377">lipo命令拆分、合并iOS静态库</a></li></ul>]]></content>
<categories>
<category>macos</category>
</categories>
<tags>
<tag>Tool</tag>
<tag>MacOS</tag>
</tags>
</entry>
<entry>
<title>winget</title>
<link href="/windows/winget/"/>
<url>/windows/winget/</url>
<content type="html"><![CDATA[<h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><p><a href="https://learn.microsoft.com/zh-cn/windows/package-manager/winget">包管理器</a></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 安装包</span><br>winget install Microsoft.VisualStudioCode<br>winget install Git.Git<br>winget install Kitware.CMake<br>winget install LLVM.LLVM<br>winget install GoLang.Go.1.19<br><span class="hljs-comment"># 升级包</span><br>winget upgrade --<span class="hljs-built_in">id</span> Git.Git <span class="hljs-comment"># 仅升级 Git</span><br>winget upgrade --all <span class="hljs-comment"># 升级所有包</span><br><span class="hljs-comment"># 查找命令位置</span><br>where.exe git<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>windows</category>
</categories>
<tags>
<tag>Tool</tag>
<tag>Windows</tag>
</tags>
</entry>
<entry>
<title>CUDA</title>
<link href="/cuda/cuda/"/>
<url>/cuda/cuda/</url>
<content type="html"><![CDATA[<!--- [概述](#概述)- [应用](#应用)- [参考文献](#参考文献)--><h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><p>CUDA(Compute Unified Device Architecture,统一计算架构)是由 NVIDIA 所推出的一种集成技术,是该公司对于 GPGPU 的正式名称。通过这个技术,用户可利用 NVIDIA 的 GeForce 8 以后的 GPU 和较新的 Quadro GPU 进行计算。亦是首次可以利用 GPU 作为 C-编译器的开发环境。NVIDIA 营销的时候,往往将编译器与架构混合推广,造成混乱。实际上,CUDA 可以兼容 OpenCL 或者自家的 C-编译器。无论是 CUDA C-语言或是 OpenCL,指令最终都会被驱动程序转换成 PTX 代码,交由显示核心计算。</p><p><code>__global__</code>:被称为内核函数,在 host 上被调用,在 device 上执行;只能返回 void 类型,不能作为类的成员函数;异步。<br><code>__device__</code>:只能在 device 上被调用,在 device 上执行,用于在 device 代码中内部调用。<br><code>__host__</code>:只能在 host 上被调用,在 host 上执行,也就是 host 上的函数,可以省略。</p><table><thead><tr><th>function</th><th>called</th><th>work</th></tr></thead><tbody><tr><td><code>__global__ void kernel_fun()</code></td><td>host</td><td>device</td></tr><tr><td><code>__device__ float device_fun()</code></td><td>device</td><td>device</td></tr><tr><td><code>__host__ float host_fun()</code></td><td>host</td><td>host</td></tr></tbody></table><p>Streaming Multiprocessors, SM, 流式多处理器</p><h2 id="应用"><a href="#应用" class="headerlink" title="应用"></a>应用</h2><p><code>sudo apt install nvidia-cuda-toolkit nvidia-profiler nvidia-visual-profiler nvidia-cuda-doc nvidia-cuda-dev</code></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdio.h></span></span><br>__global__ <span class="hljs-type">void</span> <span class="hljs-title function_">vector_add</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">int</span> *a, <span class="hljs-type">const</span> <span class="hljs-type">int</span> *b, <span class="hljs-type">int</span> *c)</span><br>{<br> *c = *a + *b;<br>}<br><span class="hljs-type">int</span> <span class="hljs-title function_">main</span><span class="hljs-params">(<span class="hljs-type">void</span>)</span><br>{<br> <span class="hljs-type">const</span> <span class="hljs-type">int</span> a = <span class="hljs-number">2</span>, b = <span class="hljs-number">5</span>;<br> <span class="hljs-type">int</span> c = <span class="hljs-number">0</span>;<br> <span class="hljs-type">int</span> *dev_a, *dev_b, *dev_c;<br> cudaMalloc((<span class="hljs-type">void</span> **)&dev_a, <span class="hljs-keyword">sizeof</span>(<span class="hljs-type">int</span>));<br> cudaMalloc((<span class="hljs-type">void</span> **)&dev_b, <span class="hljs-keyword">sizeof</span>(<span class="hljs-type">int</span>));<br> cudaMalloc((<span class="hljs-type">void</span> **)&dev_c, <span class="hljs-keyword">sizeof</span>(<span class="hljs-type">int</span>));<br> cudaMemcpy(dev_a, &a, <span class="hljs-keyword">sizeof</span>(<span class="hljs-type">int</span>), cudaMemcpyHostToDevice);<br> cudaMemcpy(dev_b, &b, <span class="hljs-keyword">sizeof</span>(<span class="hljs-type">int</span>), cudaMemcpyHostToDevice);<br> vector_add<<<<span class="hljs-number">1</span>, <span class="hljs-number">1</span>>>>(dev_a, dev_b, dev_c);<br> cudaMemcpy(&c, dev_c, <span class="hljs-keyword">sizeof</span>(<span class="hljs-type">int</span>), cudaMemcpyDeviceToHost);<br> <span class="hljs-built_in">printf</span>(<span class="hljs-string">"%d + %d = %d, Is that right?\n"</span>, a, b, c);<br> cudaFree(dev_a);<br> cudaFree(dev_b);<br> cudaFree(dev_c);<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><p>编译:<code>nvcc main.cu</code><br>运行:<code>./a.out</code></p><p>输出结果:<code>2 + 5 = 0, Is that right?</code></p><h2 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h2><ul><li><a href="https://docs.nvidia.com/cuda/cuda-c-programming-guide">CUDA C++ Programming Guide</a></li><li><a href="https://bingliu221.gitbooks.io/learn-cuda-the-simple-way/content/chapter2.html">Cuda 简单入门教程</a></li><li><a href="https://zhuanlan.zhihu.com/p/442508630">CUDA 编程 (目录)</a></li><li><a href="https://zhuanlan.zhihu.com/p/442052342">CUDA 编程(一):CUDA C 编程及 GPU 基本知识</a></li><li><a href="https://juejin.cn/post/7219216676507402297">CUDA 教程-如何用 CMake 编译 CUDA 代码</a></li><li><a href="https://zhuanlan.zhihu.com/p/620194070">CUDA 教程-如何用 CMake 编译 CUDA 代码</a></li></ul>]]></content>
<categories>
<category>cuda</category>
</categories>
<tags>
<tag>CUDA</tag>
</tags>
</entry>
<entry>
<title>Shell</title>
<link href="/tools/shell/"/>
<url>/tools/shell/</url>
<content type="html"><![CDATA[<h2 id="基础"><a href="#基础" class="headerlink" title="基础"></a>基础</h2><p><code>{}</code>是为了指定变量名范围,如<code>${AAA}_BBB</code>,否则会将<code>AAA_BBB</code>当作一个整体来解析,这就不对了。</p><h2 id="技巧"><a href="#技巧" class="headerlink" title="技巧"></a>技巧</h2><p>遍历目录下文件并解压:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-meta">#!/bin/bash</span><br><span class="hljs-function"><span class="hljs-title">print_help</span></span>() {<br> <span class="hljs-built_in">echo</span> <span class="hljs-string">"examples:"</span><br> <span class="hljs-built_in">echo</span> <span class="hljs-string">"./unzip.sh /data/file.zip"</span><br>}<br><br><span class="hljs-keyword">if</span> [ <span class="hljs-variable">$#</span> == 0 ]; <span class="hljs-keyword">then</span><br> print_help<br> <span class="hljs-built_in">exit</span> 0<br><span class="hljs-keyword">fi</span><br><br>DataDir=<span class="hljs-variable">$1</span><br><span class="hljs-keyword">for</span> File <span class="hljs-keyword">in</span> <span class="hljs-string">"<span class="hljs-variable">$DataDir</span>"</span>/*.zip; <span class="hljs-keyword">do</span><br> OutputDir=<span class="hljs-variable">${File%.*}</span><br> <span class="hljs-keyword">if</span> [ -f <span class="hljs-string">"<span class="hljs-variable">$File</span>"</span> ]; <span class="hljs-keyword">then</span><br> unzip -o <span class="hljs-string">"<span class="hljs-variable">$File</span>"</span> -d <span class="hljs-string">"<span class="hljs-variable">$OutputDir</span>"</span><br> <span class="hljs-keyword">fi</span><br><span class="hljs-keyword">done</span><br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>tools</category>
</categories>
<tags>
<tag>Tool</tag>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title>FlatBuffers</title>
<link href="/tools/flatbuffers/"/>
<url>/tools/flatbuffers/</url>
<content type="html"><![CDATA[<h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><p><a href="https://github.com/google/flatbuffers">GitHub FlatBuffers</a></p><h2 id="使用技巧"><a href="#使用技巧" class="headerlink" title="使用技巧"></a>使用技巧</h2><ol><li>flatc 和 libflatbuffers.a 版本要统一,否则运行时会崩溃。</li><li>生成 cpp 头文件:<code>flatc --cpp --gen-mutable --gen-object-api -o fbscpp *.fbs</code><br>将 json 转换为 fbsbin:<code>flatc --binary -o fbsbin sample.fbs sample.json</code>,当有多个 fbs 文件时,仅指定定义<code>root_type</code>的文件名即可,否则会报错<code>error: no root type set to parse json with</code></li><li>proto 转换为 fbs:<code>flatc --proto -o fbs proto/*.proto</code></li></ol><h2 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h2><ul><li><a href="https://google.github.io/flatbuffers/">Google FlatBuffers</a></li><li><a href="https://halfrost.com/flatbuffers_schema/">深入浅出 FlatBuffers 之 Schema</a></li></ul>]]></content>
<categories>
<category>tools</category>
</categories>
<tags>
<tag>Tool</tag>
</tags>
</entry>
<entry>
<title>Model View Controller</title>
<link href="/design-pattern/mvc/"/>
<url>/design-pattern/mvc/</url>
<content type="html"><![CDATA[<h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><ul><li>Model(模型),代表一个存取数据的对象,也可以带有逻辑,在数据变化时更新控制器。</li><li>View(视图),视图代表模型包含的数据的可视化。</li><li>Controller(控制器),控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。</li></ul><p><img src="/design-pattern/mvc/images/mvc.png" alt="MVC"></p><h2 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h2><ul><li><a href="https://www.runoob.com/design-pattern/mvc-pattern.html">MVC 模式</a></li></ul>]]></content>
<categories>
<category>design pattern</category>
</categories>
<tags>
<tag>DesignPattern</tag>
</tags>
</entry>
<entry>
<title>Singleton Pattern</title>
<link href="/design-pattern/singleton/"/>
<url>/design-pattern/singleton/</url>
<content type="html"><![CDATA[<h2 id="1-概述"><a href="#1-概述" class="headerlink" title="1 概述"></a>1 概述</h2><p>单例模式 (Singleton Pattern,也称为单件模式),是为了保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。</p><ul><li><p>定义一个单例类:</p><ol><li>私有化它的构造函数和析构函数,防止外界创建单例类的对象;</li><li>私有化或者删除它的拷贝构造函数;</li><li>使用类的私有静态指针变量指向类的唯一实例;</li><li>使用一个公有的静态方法获取该实例。</li></ol></li><li><p>使用场景:</p><ol><li>要求生产唯一序列号;</li><li>WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来;</li><li>创建对象需要消耗的资源过多,比如 I/O 与数据库的连接等。</li></ol></li><li><p>优点:</p><ol><li>在内存中只有一个实例,减少了内存的开销,尤其是在频繁的创建和销毁实例的场景下;</li><li>避免对资源的多重占用。</li></ol></li><li><p>缺点</p><ol><li>不能继承;</li><li>与单一原则冲突(一个类应该之关心内部逻辑,而不关系外面怎么实例化)。</li></ol></li></ul><p>在 C++11 之前需要考虑多线程情况下的安全问题,可通过同步锁解决,防止多线程同时进入造成多次实例化。</p><h2 id="2-Lazy-Singleton"><a href="#2-Lazy-Singleton" class="headerlink" title="2 Lazy Singleton"></a>2 Lazy Singleton</h2><p>单例实例在第一次使用时才进行初始化,如果没有地方用,单例也就不会实例话,相当于没用。</p><h3 id="2-1-基础版"><a href="#2-1-基础版" class="headerlink" title="2.1 基础版"></a>2.1 基础版</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Singleton</span><br>{<br><span class="hljs-keyword">private</span>:<br> <span class="hljs-type">static</span> Singleton *instance;<br><br><span class="hljs-keyword">private</span>:<br> <span class="hljs-built_in">Singleton</span>() {}<br> <span class="hljs-built_in">Singleton</span>(<span class="hljs-type">const</span> Singleton &) = <span class="hljs-keyword">delete</span>;<br> ~<span class="hljs-built_in">Singleton</span>() {}<br><br><span class="hljs-keyword">public</span>:<br> <span class="hljs-function"><span class="hljs-type">static</span> Singleton *<span class="hljs-title">getInstance</span><span class="hljs-params">()</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-keyword">if</span> (instance == <span class="hljs-literal">nullptr</span>)<br> {<br> instance = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Singleton</span>();<br> }<br> <span class="hljs-keyword">return</span> instance;<br> }<br>};<br></code></pre></td></tr></table></figure><p>这种方式理解简单,所以也被称为教学版,但是存在线程不安全的问题。当多个线程同时使用单例时,可能存在第一次初始化几个实例的问题。</p><h3 id="2-2-升级版"><a href="#2-2-升级版" class="headerlink" title="2.2 升级版"></a>2.2 升级版</h3><ul><li>使用智能指针</li></ul><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Singleton</span><br>{<br><span class="hljs-keyword">private</span>:<br> <span class="hljs-type">static</span> std::unique_ptr<Singleton> singleton;<br><br><span class="hljs-keyword">private</span>:<br> <span class="hljs-built_in">Singleton</span>() {}<br> <span class="hljs-built_in">Singleton</span>(<span class="hljs-type">const</span> Singleton &) = <span class="hljs-keyword">delete</span>;<br> ~<span class="hljs-built_in">Singleton</span>() {}<br><br><span class="hljs-keyword">public</span>:<br> <span class="hljs-function"><span class="hljs-type">static</span> std::unique_ptr<Singleton> &<span class="hljs-title">getInstance</span><span class="hljs-params">()</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-keyword">if</span> (singleton == <span class="hljs-literal">nullptr</span>)<br> {<br> singleton = std::<span class="hljs-built_in">make_unique</span><Singleton>(<span class="hljs-keyword">new</span> Singleton);<br> }<br> <span class="hljs-keyword">return</span> singleton;<br> }<br>};<br></code></pre></td></tr></table></figure><ul><li>使用静态的嵌套类对象</li></ul><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Singleton</span><br>{<br><span class="hljs-keyword">private</span>:<br> <span class="hljs-type">static</span> Singleton *instance;<br><br><span class="hljs-keyword">private</span>:<br> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Deletor</span><br> {<br> <span class="hljs-keyword">public</span>:<br> ~<span class="hljs-built_in">Deletor</span>()<br> {<br> <span class="hljs-keyword">if</span> (Singleton::instance != <span class="hljs-literal">nullptr</span>)<br> {<br> <span class="hljs-keyword">delete</span> Singleton::instance;<br> }<br> }<br> };<br> <span class="hljs-type">static</span> Deletor deletor;<br><br><span class="hljs-keyword">private</span>:<br> <span class="hljs-built_in">Singleton</span>() {}<br> <span class="hljs-built_in">Singleton</span>(<span class="hljs-type">const</span> Singleton &) = <span class="hljs-keyword">delete</span>;<br> ~<span class="hljs-built_in">Singleton</span>() {}<br><br><span class="hljs-keyword">public</span>:<br> <span class="hljs-function"><span class="hljs-type">static</span> Singleton *<span class="hljs-title">getInstance</span><span class="hljs-params">()</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-keyword">if</span> (instance == <span class="hljs-literal">nullptr</span>)<br> {<br> instance = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Singleton</span>();<br> }<br> <span class="hljs-keyword">return</span> instance;<br> }<br>};<br></code></pre></td></tr></table></figure><p>初始化时,在单例类内定义私有的专门用于释放的静态成员<code>deletor</code>,当程序运行结束时,利用程序在结束时析构全局变量的特性,系统会调用静态成员<code>deletor</code>的析构函数,该析构函数会删除单例的唯一实例,解决了内存泄漏的问题。</p><p>这个方式在单线程环境下是正确的,但是拿到多线程环境下就会出现 <a href="https://en.wikipedia.org/wiki/Race_condition">race condition</a>,要使其能在多线程环环境下正常,可以考虑加锁。</p><h3 id="2-3-进阶版"><a href="#2-3-进阶版" class="headerlink" title="2.3 进阶版"></a>2.3 进阶版</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Singleton</span><br>{<br><span class="hljs-keyword">private</span>:<br> <span class="hljs-type">static</span> Singleton *instance;<br><br><span class="hljs-keyword">private</span>:<br> <span class="hljs-built_in">Singleton</span>() {}<br> <span class="hljs-built_in">Singleton</span>(<span class="hljs-type">const</span> Singleton &);<br> ~<span class="hljs-built_in">Singleton</span>() {}<br><br><span class="hljs-keyword">private</span>:<br> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Deletor</span><br> {<br> <span class="hljs-keyword">public</span>:<br> ~<span class="hljs-built_in">Deletor</span>()<br> {<br> <span class="hljs-keyword">if</span> (Singleton::instance != <span class="hljs-literal">nullptr</span>)<br> {<br> <span class="hljs-keyword">delete</span> Singleton::instance;<br> }<br> }<br> };<br> <span class="hljs-type">static</span> Deletor deletor;<br><br><span class="hljs-keyword">public</span>:<br> <span class="hljs-function"><span class="hljs-type">static</span> Singleton *<span class="hljs-title">getInstance</span><span class="hljs-params">()</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-keyword">if</span> (instance == <span class="hljs-literal">nullptr</span>)<br> {<br> Lock lock; <span class="hljs-comment">// 基于作用域的加锁,超出作用域,自动调用析构函数解锁</span><br> <span class="hljs-keyword">if</span> (instance == <span class="hljs-literal">nullptr</span>)<br> {<br> instance = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Singleton</span>();<br> }<br> }<br> <span class="hljs-keyword">return</span> instance;<br> }<br>};<br></code></pre></td></tr></table></figure><p>线程安全问题仅出现在第一次初始化的时候,后面获取该实例的时候并不会遇到,也就没有必要再使用 lock,因为每次获取锁的状态都是有性能损耗的。</p><p>双检测锁很好地解决了这个问题,它通过加锁前检测是否已经初始化,避免了每次获取实例时都要首先获取锁资源。</p><p>加入 DCL: Double-Checked Locking Pattern 后,其实还是有问题的,关于 <a href="https://en.wikipedia.org/wiki/Memory_model_(programming)">memory model</a>。</p><p>在某些内存模型中或者是由于编译器的优化以及运行时优化等原因,使得 instance 虽然已经不是 nullptr 但是其所指对象还没有完成构造,这种情况下,另一个线程如果调用<code>getInstance()</code>就有可能使用到一个不完全初始化的对象。换句话说,就是代码中:<code>if(instance == NULL)</code>和<code>instance = new Singleton();</code>没有正确的同步,在某种情况下会出现<code>new</code>返回了地址赋值给<code>instance</code>变量而<code>Singleton</code>此时还没有构造完全,当另一个线程随后运行到<code>if(instance == NULL)</code>时将不会进入,从而返回了不完全的实例对象给用户使用,造成了严重的错误。在 C++11 没有出来的时候,只能靠插入两个 <a href="https://en.wikipedia.org/wiki/Memory_barrier">memory barrier</a> 来解决这个错误,但是 C++11 引进了 memory model,提供了 Atomic 实现内存的同步访问,即不同线程总是获取对象修改前或修改后的值,无法在对象修改期间获得该对象。</p><p>因此,在有了 C++11 后就可以正确的跨平台的实现 DCL 模式了,利用 atomic,代码如下:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs cpp">atomic<Widget *> Widget::pInstance{<span class="hljs-literal">nullptr</span>};<br><span class="hljs-function">Widget *<span class="hljs-title">Widget::Instance</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">if</span> (pInstance == <span class="hljs-literal">nullptr</span>)<br> {<br> lock_guard<mutex> lock{mutW};<br> <span class="hljs-keyword">if</span> (pInstance == <span class="hljs-literal">nullptr</span>)<br> {<br> pInstance = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Widget</span>();<br> }<br> }<br> <span class="hljs-keyword">return</span> pInstance;<br>}<br></code></pre></td></tr></table></figure><p>C++11 中的 atomic 类的默认<code>memory_order_seq_cst</code>保证了 5、10 行代码的正确同步,由于上面的 atomic 需要一些性能上的损失,因此我们可以写一个优化的版本:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs cpp">atomic<Widget *> Widget::pInstance{<span class="hljs-literal">nullptr</span>};<br><span class="hljs-function">Widget *<span class="hljs-title">Widget::Instance</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> Widget *p = pInstance;<br> <span class="hljs-keyword">if</span> (p == <span class="hljs-literal">nullptr</span>)<br> {<br> lock_guard<mutex> lock{mutW};<br> <span class="hljs-keyword">if</span> ((p = pInstance) == <span class="hljs-literal">nullptr</span>)<br> {<br> pInstance = p = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Widget</span>();<br> }<br> }<br> <span class="hljs-keyword">return</span> p;<br>}<br></code></pre></td></tr></table></figure><h2 id="3-Eager-Singleton"><a href="#3-Eager-Singleton" class="headerlink" title="3 Eager Singleton"></a>3 Eager Singleton</h2><p>单例实例在程序运行时被立即执行初始化。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Singleton</span><br>{<br><span class="hljs-keyword">private</span>:<br> <span class="hljs-type">static</span> Singleton instance;<br><br><span class="hljs-keyword">private</span>:<br> <span class="hljs-built_in">Singleton</span>() {}<br> ~<span class="hljs-built_in">Singleton</span>() {}<br> <span class="hljs-built_in">Singleton</span>(<span class="hljs-type">const</span> Singleton &);<br> Singleton &<span class="hljs-keyword">operator</span>=(<span class="hljs-type">const</span> Singleton &);<br><br><span class="hljs-keyword">public</span>:<br> <span class="hljs-function"><span class="hljs-type">static</span> Singleton &<span class="hljs-title">getInstance</span><span class="hljs-params">()</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-keyword">return</span> instance;<br> }<br>};<br></code></pre></td></tr></table></figure><p>由于在 main 函数之前初始化,所以没有线程安全的问题。但是潜在问题在于 no-local static 对象(函数外的 static 对象)在不同编译单元中的初始化顺序是未定义的。也即<code>static Singleton instance;</code>和<code>static Singleton& getInstance();</code>二者的初始化顺序不确定,如果在初始化完成之前调用<code>getInstance()</code>方法会返回一个未定义的实例。</p><h2 id="4-Meyers-Singleton"><a href="#4-Meyers-Singleton" class="headerlink" title="4 Meyers Singleton"></a>4 Meyers Singleton</h2><p>综上所述,在 C++11 以上版本时,用下列方式是最完美的解决方案:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Singleton</span><br>{<br><span class="hljs-keyword">private</span>:<br> <span class="hljs-built_in">Singleton</span>() {}<br> ~<span class="hljs-built_in">Singleton</span>() {}<br> <span class="hljs-built_in">Singleton</span>(<span class="hljs-type">const</span> Singleton &);<br> Singleton &<span class="hljs-keyword">operator</span>=(<span class="hljs-type">const</span> Singleton &);<br><br><span class="hljs-keyword">public</span>:<br> <span class="hljs-function"><span class="hljs-type">static</span> Singleton &<span class="hljs-title">getInstance</span><span class="hljs-params">()</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-type">static</span> Singleton instance;<br> <span class="hljs-keyword">return</span> instance;<br> }<br>};<br></code></pre></td></tr></table></figure><h2 id="5-总结"><a href="#5-总结" class="headerlink" title="5 总结"></a>5 总结</h2><ul><li>Lazy Singleton 通常需要加锁来保证线程安全;</li><li>Eager Singleton 虽然是线程安全的,但存在潜在问题;</li><li>Meyers Singleton 最优雅,但局部静态变量版本在 C++11 后才是线程安全的。</li></ul><p>单例模式本质就是统一管理一堆全局变量,用命名空间定义一堆静态方法和静态变量也可以实现。</p><h2 id="6-参考文献"><a href="#6-参考文献" class="headerlink" title="6 参考文献"></a>6 参考文献</h2><ul><li><a href="https://zhuanlan.zhihu.com/p/37469260">C++ 单例模式</a></li><li><a href="https://lday.me/2017/12/02/0018_cpp_atomic_summary/">C++ 内存屏障(内存顺序)总结</a></li><li><a href="https://en.wikipedia.org/wiki/Race_condition">Race condition</a></li><li><a href="https://en.wikipedia.org/wiki/Memory_model_(programming)">Memory model</a></li><li><a href="https://en.wikipedia.org/wiki/Memory_barrier">Memory barrier</a></li></ul>]]></content>
<categories>
<category>design pattern</category>
</categories>
<tags>
<tag>CPP</tag>
<tag>DesignPattern</tag>
</tags>
</entry>
<entry>
<title>Rsync</title>
<link href="/tools/rsync/"/>
<url>/tools/rsync/</url>
<content type="html"><![CDATA[<h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># Debian</span><br>$ sudo apt-get install rsync<br><span class="hljs-comment"># Red Hat</span><br>$ sudo yum install rsync<br><span class="hljs-comment"># Arch Linux</span><br>$ sudo pacman -S rsync<br></code></pre></td></tr></table></figure><h2 id="基本用法"><a href="#基本用法" class="headerlink" title="基本用法"></a>基本用法</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">rsync -a source1 source2 destination<br></code></pre></td></tr></table></figure><ul><li><code>-r</code>,表示递归,即包含子目录,<code>-r</code>是必须的,否则<code>rsync</code>运行不会成功。</li><li><code>-a</code>,<code>--archive</code>,表示存档模式,保存所有的元数据,比如修改时间(modification time)、权限、所有者等,并且软链接也会同步过去。由于 rsync 默认使用文件大小和修改时间决定文件是否需要更新,所以<code>-a</code>比<code>-r</code>更有用。</li><li><code>-n</code></li><li><code>--delete</code></li><li><code>--exclude</code></li><li><code>--include</code></li><li><code>--link-dest</code></li></ul><h2 id="使用-SSH-协议"><a href="#使用-SSH-协议" class="headerlink" title="使用 SSH 协议"></a>使用 SSH 协议</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">rsync -av -e <span class="hljs-string">'ssh -p 2234'</span> <span class="hljs-built_in">source</span>/ user@remote_host:/destination<br></code></pre></td></tr></table></figure><h2 id="使用-rsync-协议"><a href="#使用-rsync-协议" class="headerlink" title="使用 rsync 协议"></a>使用 rsync 协议</h2><p>命令格式:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">rsync -av <span class="hljs-built_in">source</span>/ remote_host::module/destination<br>rsync -av <span class="hljs-built_in">source</span>/ rsync://remote_host/module/destination<br></code></pre></td></tr></table></figure><p>匿名用户:</p><ol><li><p>服务端配置</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># /etc/rsyncd.conf</span><br>uid = nobody<br>gid = nobody<br>use <span class="hljs-built_in">chroot</span> = no<br>max connections = 4<br>syslog facility = local5<br>pid file = /var/run/rsyncd.pid<br><br>[tmp]<br>uid = mqq<br>gid = mqq<br>path = /home/mqq<br>comment = tmp <span class="hljs-built_in">sync</span><br><span class="hljs-built_in">read</span> only = <span class="hljs-literal">false</span><br></code></pre></td></tr></table></figure></li><li><p>服务端执行<code>rsync --daemon</code>启动服务</p></li><li><p>客户端执行</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">rsync -av file server::tmp<br></code></pre></td></tr></table></figure></li></ol><p>指定用户:</p><ol><li><p>服务端配置</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># /etc/rsyncd.conf</span><br>uid = nobody<br>gid = nobody<br>use <span class="hljs-built_in">chroot</span> = no<br>max connections = 4<br>syslog facility = local5<br>pid file = /var/run/rsyncd.pid<br>secrets file = /etc/rsyncd.secrets<br><br>[tmp]<br>uid = mqq<br>gid = mqq<br>path = /home/mqq<br>comment = tmp <span class="hljs-built_in">sync</span><br><span class="hljs-built_in">read</span> only = <span class="hljs-literal">false</span><br>auth <span class="hljs-built_in">users</span> = qq<br><br><span class="hljs-comment"># /etc/rsyncd.secrets</span><br><span class="hljs-built_in">echo</span> <span class="hljs-string">"qq:123456"</span> > /etc/rsyncd.secrets<br><span class="hljs-built_in">chmod</span> 600 /etc/rsyncd.secrets<br></code></pre></td></tr></table></figure></li><li><p>服务端执行<code>rsync --daemon</code>启动服务</p></li><li><p>客户端配置</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">"123456"</span> > rsyncd.secrets<br><span class="hljs-built_in">chmod</span> 600 rsyncd.secrets<br></code></pre></td></tr></table></figure></li><li><p>客户端执行</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">rsync -av --password-file=rsyncd.secrets file qq@server::tmp<br></code></pre></td></tr></table></figure></li></ol><h2 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h2><ul><li><a href="https://www.ruanyifeng.com/blog/2020/08/rsync.html">rsync 用法教程</a></li></ul>]]></content>
<categories>
<category>tools</category>
</categories>
<tags>
<tag>Tool</tag>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title>C++ Timer</title>
<link href="/cpp/timer/"/>
<url>/cpp/timer/</url>
<content type="html"><![CDATA[<h2 id="1-time-t"><a href="#1-time-t" class="headerlink" title="1 time_t"></a>1 time_t</h2><p>time_t 计时精确秒,就是相当于获取当时的时间</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><time.h></span></span><br><span class="hljs-type">time_t</span> t;<br><span class="hljs-keyword">struct</span> <span class="hljs-title class_">tm</span> *timeinfo;<br><span class="hljs-built_in">time</span>(&t);<br>timeinfo = <span class="hljs-built_in">localtime</span>(&t);<br><span class="hljs-built_in">printf</span>(<span class="hljs-string">"%s"</span>, <span class="hljs-built_in">asctime</span>(timeinfo));<br></code></pre></td></tr></table></figure><h2 id="2-clock-t"><a href="#2-clock-t" class="headerlink" title="2 clock_t"></a>2 clock_t</h2><p>clock_t 获取的是进程调用 CPU 的时间,多核情况下不准确</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><time.h></span></span><br><span class="hljs-type">clock_t</span> start, finish;<br>start = <span class="hljs-built_in">clock</span>();<br>finish = <span class="hljs-built_in">clock</span>();<br><span class="hljs-built_in">printf</span>(<span class="hljs-string">"main: %f ms\n"</span>, ((<span class="hljs-type">double</span>)(finish - start) / <span class="hljs-number">1000</span>));<br></code></pre></td></tr></table></figure><h2 id="3-gettimeofday"><a href="#3-gettimeofday" class="headerlink" title="3 gettimeofday"></a>3 gettimeofday</h2><p>这种方式可以精确到微秒获取程序运行耗费的时间</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><sys/time.h></span></span><br><span class="hljs-keyword">struct</span> <span class="hljs-title class_">timeval</span> start, end;<br><span class="hljs-built_in">gettimeofday</span>(&start, <span class="hljs-literal">NULL</span>);<br><span class="hljs-built_in">gettimeofday</span>(&end1, <span class="hljs-literal">NULL</span>);<br><span class="hljs-type">double</span> timeuse = (<span class="hljs-type">double</span>)(<span class="hljs-number">1000000</span> * (end1.tv_sec - start1.tv_sec) + (end1.tv_usec - start1.tv_usec)) / <span class="hljs-number">1000</span>;<br><span class="hljs-built_in">printf</span>(<span class="hljs-string">"%f\n"</span>, timeuse); <span class="hljs-comment">// ms</span><br></code></pre></td></tr></table></figure><h2 id="4-std-chrono"><a href="#4-std-chrono" class="headerlink" title="4 std::chrono"></a>4 std::chrono</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><chrono></span></span><br><span class="hljs-keyword">struct</span> <span class="hljs-title class_">Timer</span><br>{<br> std::chrono::system_clock::time_point start, end;<br> std::chrono::duration<<span class="hljs-type">float</span>> duration;<br><br> <span class="hljs-built_in">Timer</span>()<br> {<br> start = std::chrono::high_resolution_clock::<span class="hljs-built_in">now</span>();<br> }<br> ~<span class="hljs-built_in">Timer</span>()<br> {<br> end = std::chrono::high_resolution_clock::<span class="hljs-built_in">now</span>();<br> duration = end - start;<br> <span class="hljs-type">const</span> <span class="hljs-type">float</span> seconds = duration.<span class="hljs-built_in">count</span>();<br> <span class="hljs-keyword">if</span> (seconds < <span class="hljs-number">1</span>) {<br> std::cout << <span class="hljs-string">"Timer took "</span> << seconds * <span class="hljs-number">1000.0f</span> << <span class="hljs-string">"ms"</span> << std::endl;<br> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (seconds < <span class="hljs-number">60</span>) {<br> std::cout << <span class="hljs-string">"Timer took "</span> << seconds << <span class="hljs-string">"s"</span> << std::endl;<br> } <span class="hljs-keyword">else</span> {<br> std::cout << <span class="hljs-string">"Timer took "</span> << seconds / <span class="hljs-number">60</span> << <span class="hljs-string">"min"</span> << std::endl;<br> }<br> }<br>};<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>cpp</category>
</categories>
<tags>
<tag>CPP</tag>
</tags>
</entry>
<entry>
<title>crontab</title>
<link href="/tools/crontab/"/>
<url>/tools/crontab/</url>
<content type="html"><![CDATA[<h2 id="Overview"><a href="#Overview" class="headerlink" title="Overview"></a>Overview</h2><p>crond 是 linux 用来定期执行程序的命令。当安装完成操作系统之后,默认便会启动此任务调度命令。crond 命令每分种会定期检查是否有要执行的工作,如果有要执行的工作便会自动执行该工作。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo apt install cron <span class="hljs-comment"># debian 安装 cron</span><br>sudo yum install cron <span class="hljs-comment"># centos 安装 cron</span><br><br>/sbin/service crond start <span class="hljs-comment"># 启动服务</span><br>/sbin/service crond stop <span class="hljs-comment"># 关闭服务</span><br>/sbin/service crond restart <span class="hljs-comment"># 重启服务</span><br>/sbin/service crond reload <span class="hljs-comment"># 重新载入配置</span><br><br><span class="hljs-built_in">cat</span> /etc/crontab <span class="hljs-comment"># 默认定时任务</span><br>crontab -l <span class="hljs-comment"># 查看定时任务</span><br>crontab -e <span class="hljs-comment"># 编辑定时任务</span><br>/etc/crontab <span class="hljs-comment"># 默认配置文件路径</span><br>/var/spool/cron/crontabs/ <span class="hljs-comment"># 用户配置文件路径</span><br><br>run-parts --<span class="hljs-built_in">test</span> /etc/cron.daily <span class="hljs-comment"># 测试天级任务脚本</span><br>run-parts --report /etc/cron.daily <span class="hljs-comment"># 执行天级任务脚本</span><br></code></pre></td></tr></table></figure><blockquote><p>/etc/cron.daily 目录下的脚本不可带后缀,默认以 root 用户执行</p></blockquote><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><ul><li><a href="https://blog.csdn.net/xiyuan1999/article/details/8160998">linux 定时任务的设置 crontab 配置指南</a></li><li><a href="https://medium.com/@marsztw/etc-cron-hourly-daily-weekly-monthly-%E7%9A%84%E7%94%A8%E6%B3%95-69433f3df62">/etc/cron.{hourly|daily|weekly|monthly} 的用法</a></li><li><a href="https://docs.oracle.com/cd/E24847_01/html/819-6951/sysrescron-24589.html">创建和编辑 crontab 文件</a></li></ul>]]></content>
<categories>
<category>tools</category>
</categories>
<tags>
<tag>Tool</tag>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title>C++</title>
<link href="/cpp/cpp/"/>
<url>/cpp/cpp/</url>
<content type="html"><![CDATA[<h2 id="1-基本特性"><a href="#1-基本特性" class="headerlink" title="1 基本特性"></a>1 基本特性</h2><ul><li><a href="keywords.md">关键字</a></li><li><a href="constructor.md">构造函数</a></li><li><a href="destructor.md">析构函数</a></li><li><a href="operator.md">运算符</a></li><li><a href="%E6%8C%87%E9%92%88%E4%B8%8E%E5%BC%95%E7%94%A8.md">指针与引用</a></li><li><a href="stl.md">The C++ Standard Template Library</a></li></ul><h2 id="2-类型转换"><a href="#2-类型转换" class="headerlink" title="2 类型转换"></a>2 类型转换</h2><p>语法形式:<br>类型说明符 (表达式)<br>(类型说明符) 表达式<br>类型操作符<类型说明符>(表达式) —— C++ 特有形式</p><p>类型操作符可以是:<br>const_cast、dynamic_cast、static_cast<br>例:<code>int(z)</code>、<code>(int)z</code>、<code>static_cast<int>(z)</code> 三种完全等价。</p><h2 id="3-常用的-I-O-流类库操作符"><a href="#3-常用的-I-O-流类库操作符" class="headerlink" title="3 常用的 I/O 流类库操作符"></a>3 常用的 I/O 流类库操作符</h2><p><img src="/cpp/cpp/images/library-operators.png" alt="常用 IO 流类库操作符"></p><h2 id="4-基类与派生类"><a href="#4-基类与派生类" class="headerlink" title="4 基类与派生类"></a>4 基类与派生类</h2><ul><li><p>单个类中的访问权限:</p><ul><li>public(公有成员):在类的内部和外部都可以直接访问;</li><li>protect(保护成员):在本类的内部和派生类的内部可以直接访问,外部均不可以直接访问,外部只能通过成员函数或友元函数进行访问;</li><li>private(私有成员):在类的内部可以直接访问,外部不可以直接访问,外部只能通过成员函数或友元函数进行访问。</li></ul></li><li><p>继承方式:</p><ul><li>public:基类中的成员访问权限在派生类中不变;</li><li>protect:基类中的 public 成员在派生类中变为 protect 成员,其它不变;</li><li>private:基类中的所有成员在派生类中均变为 private 成员。</li></ul></li><li><p>派生类的构成</p><ul><li>派生类拥有基类所有的数据成员和成员函数;</li><li>派生类可以拥有基类没有的数据成员和成员函数;</li><li>可以通过访问说明符控制成员的访问权限;</li><li>派生类是一种特殊的基类, 可以将派生类对象当作父类对象使用;</li><li>友元函数不能被继承, 友元函数不是成员函数。</li><li>可以通过在派生类中声明同名的成员, 来实现修改基类成员功能的效果。</li></ul><p><img src="/cpp/cpp/images/derived-class-member.png" alt="派生类的构成"></p></li><li><p>访问属性设置的原则:</p><ul><li>需要被外界访问的成员,设置为:public;</li><li>只能在当前类中访问的成员, 设置为:private;</li><li>只能在当前类和派生类中访问的成员,设置为:protected。</li></ul><p><img src="/cpp/cpp/images/derived-class-access-properties-1.png" alt="派生类的访问控制"></p><p><img src="/cpp/cpp/images/derived-class-access-properties-2.png" alt="派生类的访问控制"></p></li></ul><h2 id="5-构造函数和析构函数"><a href="#5-构造函数和析构函数" class="headerlink" title="5 构造函数和析构函数"></a>5 构造函数和析构函数</h2><p>在我们创建新的对象的时候,都要执行某一个类中的构造函数,而当调用构造函数分配了资源之后,当我们销毁一个对象的时候需要一个相应的操作将这些资源释放出去,这就需要析构函数。一般来说,在有基类和派生类存在时,在创建派生类类型时,会先构造基类,再构造派生类,析构顺序反之,类似于进栈出栈的过程。</p><p>指针不会调用构造和析构函数:</p><p><img src="/cpp/cpp/images/example1-constructor.png" alt="example1-constructor"></p><p>当对指针用 new 在内存中开辟空间的时候会调用构造函数:</p><p><img src="/cpp/cpp/images/example2-constructor.png" alt="example2-constructor"></p><p>当我们使用 new 为指针开辟空间,然后用 delete 释放掉空间会调用构造和析构函数:</p><p><img src="/cpp/cpp/images/example3-constructor.png" alt="example3-constructor"></p><p>当我们函数的形参是一个对象的时候,这时候会系统只会调用析构函数,而缺少形参的构造函数:</p><p><img src="/cpp/cpp/images/example4-constructor.png" alt="example4-constructor"></p><p>当形参为一个对象的时候,实参也为对象,这时候系统会将实参复制一份给形参,此时系统就不会再给形参额外调用构造函数来对形参对象初始化了,所以就不会调用构造函数,但是形参被销毁的时候还是会调用析构函数!</p><p>当我们函数的形参是一个引用的时候,这时候会系统不调用构造函数和析构函数:</p><p><img src="/cpp/cpp/images/example5-constructor.png" alt="example5-constructor"></p><p>当形参为一个引用的时候,实参也对象,这时候系统会将形参指向实参,此时系统就不会对形参调用构造函数和析构函数!</p><p>构造函数存在的目的就是为了给对象在内存中开辟空间并且给对象设置一些初始值,而析构函数就是将某个对象从内存中抹除,而设置的,经典的例子就是上边的指针的例子。</p><h2 id="6-设计模式"><a href="#6-设计模式" class="headerlink" title="6 设计模式"></a>6 设计模式</h2><ul><li><a href="singleton.md">单例模式</a></li><li><a href="mvc.md">MVC 模式</a></li></ul><h2 id="7-应用"><a href="#7-应用" class="headerlink" title="7 应用"></a>7 应用</h2><p><a href="timer.md">三种计时方法</a></p><h2 id="8-参考文献"><a href="#8-参考文献" class="headerlink" title="8 参考文献"></a>8 参考文献</h2><ul><li><a href="https://cplusplus.com/">cplusplus.com</a></li><li><a href="https://zh.cppreference.com/">cppreference.com</a></li><li><a href="https://blog.csdn.net/weixin_39345003/article/details/81276968?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight">const 的用法</a></li><li><a href="https://blog.csdn.net/wjf1997/article/details/83041666">C++ 何时调用构造函数,何时调用析构函数</a></li><li><a href="https://blog.csdn.net/xiaokunzhang/article/details/80997274">派生类的定义、构成及访问控制</a></li><li><a href="https://www.cnblogs.com/tianzeng/p/9775672.html">c++ 中重载,重写,覆盖</a></li><li><a href="https://blog.csdn.net/hanxv_1987/article/details/79521102">C\C++获取系统中CPU核数</a></li></ul>]]></content>
<categories>
<category>cpp</category>
</categories>
<tags>
<tag>CPP</tag>
</tags>
</entry>
<entry>
<title>C++ Constructor</title>
<link href="/cpp/constructor/"/>
<url>/cpp/constructor/</url>
<content type="html"><![CDATA[<h2 id="1-概述"><a href="#1-概述" class="headerlink" title="1 概述"></a>1 概述</h2><h2 id="2-Constructor"><a href="#2-Constructor" class="headerlink" title="2 Constructor"></a>2 Constructor</h2><p>函数原型:<code>Constructor();</code></p><h2 id="3-Copy-Constructor"><a href="#3-Copy-Constructor" class="headerlink" title="3 Copy Constructor"></a>3 Copy Constructor</h2><p>函数原型:<code>Constructor(const Constructor &);</code></p><h3 id="3-1-调用场景"><a href="#3-1-调用场景" class="headerlink" title="3.1 调用场景"></a>3.1 调用场景</h3><ul><li>对象作为函数的参数,以值传递的方式传给函数;</li><li>对象作为函数的返回值,以值的形式从函数返回;</li><li>使用一个对象给另一个对象初始化。</li></ul><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">example</span><span class="hljs-params">(ClassType class_name)</span></span>;<br><span class="hljs-function">ClassType <span class="hljs-title">example</span><span class="hljs-params">(<span class="hljs-type">void</span>)</span></span>;<br><br><span class="hljs-function">ClassType <span class="hljs-title">c1</span><span class="hljs-params">()</span></span>;<br><span class="hljs-function">ClassType <span class="hljs-title">c2</span><span class="hljs-params">(c1)</span></span>;<br></code></pre></td></tr></table></figure><ul><li>对象不存在,且没用别的对象来初始化,就是调用了构造函数;</li><li>对象不存在,且用别的对象来初始化,就是拷贝构造函数;</li><li>对象存在,用别的对象来给它赋值,就是赋值函数。</li></ul><h3 id="3-2-与赋值运算符的区别"><a href="#3-2-与赋值运算符的区别" class="headerlink" title="3.2 与赋值运算符的区别"></a>3.2 与赋值运算符的区别</h3><p>拷贝构造函数使用传入对象的值生成一个新的对象的实例,而赋值运算符是将对象的值复制给一个已经存在的实例。拷贝构造函数也是一种构造函数,那么它的功能就是创建一个新的对象实例;赋值运算符是执行某种运算,将一个对象的值复制给另一个对象(已经存在的)。调用的是拷贝构造函数还是赋值运算符,主要是看是否有新的对象实例产生。如果产生了新的对象实例,那调用的就是拷贝构造函数;如果没有,那就是对已有的对象赋值,调用的是赋值运算符。拷贝构造函数是一个对象初始化一块内存区域,这块内存就是新对象的内存区,而赋值函数是对于一个已经被初始化的对象来进行赋值操作。</p><p>编译器生成默认拷贝构造函数的场景:<br>如果用户没有自定义拷贝构造函数,并且在代码中使用到了拷贝构造函数,编译器就会生成默认的拷贝构造函数。但如果用户定义了拷贝构造函数,编译器就不在生成。<br>如果用户定义了一个构造函数,但不是拷贝构造函数,而此时代码中又用到了拷贝构造函数,那编译器也会生成默认的拷贝构造函数。</p><h3 id="3-3-深拷贝与浅拷贝"><a href="#3-3-深拷贝与浅拷贝" class="headerlink" title="3.3 深拷贝与浅拷贝"></a>3.3 深拷贝与浅拷贝</h3><h2 id="4-Move-Constructor"><a href="#4-Move-Constructor" class="headerlink" title="4 Move Constructor"></a>4 Move Constructor</h2><p>函数原型:<code>Constructor(Constructor &&);</code></p><h2 id="5-特性"><a href="#5-特性" class="headerlink" title="5 特性"></a>5 特性</h2><ol><li>构造函数不能为虚函数。<br>因为构造一个对象的时候,需要知道对象的实际类型,而虚函数是在运行期间才确定实际类型。如果构造函数为虚函数,则在构造一个对象时,由于对象还未构造成功,编译器还无法知道对象的实际类型,也就无法确定是该类本身还是派生类。<br>虚函数的执行依赖虚函数表,而虚函数表是在构造函数中初始化的,即初始化为<code>vptr</code>,让它指向虚函数表。如果构造函数为虚函数,则在构造对象期间,虚函数表还没有被初始化,将无法进行。<br>在执行构造函数的函数体前,对象的内存已经分配了,函数的对应关系、虚表也已经创建了,执行构造函数的函数体时,此对象已经是一个完整的对象了。<br>编译器会在构造函数的一开始插入一部分代码,如果类中有虚函数,这段代码会创建虚表指针成员,并初始化虚表,然后执行初始化成员列表,最后才执行原本的函数体,故在执行函数体时,对象已经实例化了。</li><li>构造函数中调用虚函数的情况。<br>在基类的构造函数内调用纯虚方法会编译失败,在派生类的构造函数中调用虚函数是可行的。因为构造对象时,会先执行基类的构造函数,而此时虚表创建了,但是代表纯虚函数的函数指针还未初始化,直到执行派生类的构造函数时,虚表内的指针才指向派生类的方法,此时调用才是有效的。<br><a href="../src/CppPrimerPlus/Practice/abstract_class.cpp">abstract class 源码</a></li></ol><h2 id="6-参考文献"><a href="#6-参考文献" class="headerlink" title="6 参考文献"></a>6 参考文献</h2><ul><li><a href="https://blog.csdn.net/qq_34364654/article/details/107245276">为什么构造函数不能是虚函数?析构函数可以是虚函数吗?</a></li><li><a href="https://blog.csdn.net/gukesdo/article/details/7514080">C++ 类对象创建过程</a></li><li><a href="https://www.jianshu.com/p/f5d48a7f5a52">拷贝构造函数和移动构造函数</a></li><li><a href="https://blog.csdn.net/hebbely/article/details/65437510">赋值运算符和拷贝构造函数的区别与联系</a></li></ul>]]></content>
<categories>
<category>cpp</category>
</categories>
<tags>
<tag>CPP</tag>
</tags>
</entry>
<entry>
<title>C++ Destructor</title>
<link href="/cpp/destructor/"/>
<url>/cpp/destructor/</url>
<content type="html"><![CDATA[<h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><p>析构函数可以声明为虚函数。</p><p>作用:基类的指针指向派生类对象时,可以用基类的指针删除派生类对象,防止内存泄露。详见 <a href="./keywords.md##virtual">virtual</a>。</p><p>声明为虚函数的场景:某个类被作为基类使用时。</p><p>不建议声明为虚函数的场景:某个类不准备作为基类使用(不包含虚函数成员)时,如果声明析构函数为虚函数,在构造类对象时,会创建一个虚函数表,增加对象的内存占用,还有可能降低可移植性。</p><p>当析构函数声明为虚函数,用基类指针指向派生类对象时,执行 delete 会调用派生类的析构函数,派生类的析构函数又会自动调用基类的析构函数,从而使整个对象的资源被完全释放。<br>如果析构函数不被声明成虚函数,则编译器实施静态绑定,在删除基类指针时,就只会调用基类的析构函数而不调用派生类的析构函数,导致派生类对象析构不完全,造成内存泄漏。</p><p>无故的声明虚析构函数和永远不去声明一样是错误的。</p><h2 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h2><ul><li><a href="https://blog.csdn.net/qq_34364654/article/details/107245276">为什么构造函数不能是虚函数?析构函数可以是虚函数吗?</a></li></ul>]]></content>
<categories>
<category>cpp</category>
</categories>
<tags>
<tag>CPP</tag>
</tags>
</entry>
<entry>
<title>C++ Keywords</title>
<link href="/cpp/keywords/"/>
<url>/cpp/keywords/</url>
<content type="html"><![CDATA[<h2 id="const"><a href="#const" class="headerlink" title="const"></a>const</h2><ul><li>避免无意中修改数据。</li><li>能够处理 const 和非 const 实参,否则只能接收非 const 数据。</li><li>使函数能够正确生成并使用临时变量。</li></ul><p>const 是 constant 的缩写,“恒定不变”的意思。被 const 修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。所以很多 C++ 程序设计书籍建议:“Use const whenever you need”。s</p><p>如果参数作输出用,不论它是什么数据类型,也不论它采用“指针传递”还是“引用传递”,都不能加 const 修饰,否则该参数将失去输出功能。const 只能修饰输入参数,如果输入参数采用“指针传递”,那么加 const 修饰可以防止意外地改动该指针,起到保护作用。</p><ul><li><p>函数返回值不可作为左值。在“指针传递”和“引用传递”时可以加<code>const</code>修饰,但是在“值传递”的情况下,由于函数将自动产生临时变量用于复制该参数,该输入参数本来就无需保护,所以不要加<code>const</code>修饰。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-function"><span class="hljs-type">const</span> <span class="hljs-type">int</span> *<span class="hljs-title">fun</span><span class="hljs-params">(<span class="hljs-type">int</span> *xxx)</span> </span>{}<br><span class="hljs-function"><span class="hljs-type">const</span> <span class="hljs-type">int</span> &<span class="hljs-title">fun</span><span class="hljs-params">(<span class="hljs-type">int</span> &xxx)</span> </span>{}<br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">fun</span><span class="hljs-params">(<span class="hljs-type">int</span> xxx)</span> </span>{}<br></code></pre></td></tr></table></figure></li><li><p>形参在本函数内不能作为左值。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-function"><span class="hljs-type">int</span> *<span class="hljs-title">fun</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">int</span> *xxx)</span> </span>{}<br><span class="hljs-function"><span class="hljs-type">int</span> &<span class="hljs-title">fun</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">int</span> &xxx)</span> </span>{}<br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">fun</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">int</span> xxx)</span> </span>{}<br></code></pre></td></tr></table></figure></li><li><p>任何不会修改数据成员的函数都应该声明为 const 类型。此种写法表示本函数不会修改本对象中的成员变量。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-function"><span class="hljs-type">int</span>* <span class="hljs-title">fun</span><span class="hljs-params">(<span class="hljs-type">int</span>* xxx)</span> <span class="hljs-type">const</span> </span>{}<br></code></pre></td></tr></table></figure></li></ul><h2 id="extern"><a href="#extern" class="headerlink" title="extern"></a>extern</h2><ol><li>单定义规则<ol><li>变量只能被定义一次;</li><li>定义声明(defining declaration,简称定义);</li><li>引用声明(referencing declaration,简称声明);</li></ol></li><li>一个变量多处使用,仅在其中一个文件中包含定义,在使用该变量的其它文件中使用该关键字声明</li></ol><h2 id="static"><a href="#static" class="headerlink" title="static"></a>static</h2><p>隐藏,保持内容持久,默认初始化为 0</p><ul><li>静态全局变量,全局生命周期,本文件可见。</li><li>静态局部变量,全局生命周期,仅局部可见。</li><li>静态函数,全局生命周期,全局可见。</li><li>静态成员变量,全局生命周期,同类对象共享一份。</li><li>静态成员函数,全局生命周期,同类对象共享一份。</li></ul><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-type">int</span> global = <span class="hljs-number">200</span>; <span class="hljs-comment">// 全局可见</span><br><span class="hljs-type">static</span> <span class="hljs-type">int</span> current_file = <span class="hljs-number">100</span>; <span class="hljs-comment">// 本文件可见</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">fun</span><span class="hljs-params">(<span class="hljs-type">int</span> a)</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-comment">// code</span><br> <span class="hljs-type">static</span> llama = <span class="hljs-number">0</span>; <span class="hljs-comment">// 仅局部可见</span><br>}<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span> {<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">void</span> <span class="hljs-title">fun</span><span class="hljs-params">()</span></span>; <span class="hljs-comment">// 同类对象共享一份</span><br><span class="hljs-keyword">private</span>:<br> <span class="hljs-type">static</span> <span class="hljs-type">int</span> a; <span class="hljs-comment">// 同类对象共享一份</span><br>}<br></code></pre></td></tr></table></figure><h2 id="inline"><a href="#inline" class="headerlink" title="inline"></a>inline</h2><p>内联函数是函数,有类型检查,语法判断等,在编译时展开,嵌入代码中。<br>宏定义在预编译阶段展开,只是简单的文本替换。</p><h2 id="virtual"><a href="#virtual" class="headerlink" title="virtual"></a>virtual</h2><p>虚函数是为了实现多态,析构函数是为了在对象不被使用之后释放它的资源。</p><p>那么把析构函数声明为 virtual 有什么作用呢?</p><p>直接的讲,C++ 中基类采用 virtual 虚析构函数是为了防止内存泄漏。</p><p>具体地说,如果派生类中申请了内存空间,并在其析构函数中对这些内存空间进行释放。假设基类中采用的是非虚析构函数,当删除基类指针指向的派生类对象时就不会触发动态绑定,因而只会调用基类的析构函数,而不会调用派生类的析构函数。那么在这种情况下,派生类中申请的空间就得不到释放从而产生内存泄漏。所以,为了防止这种情况的发生,基类的析构函数应采用 virtual 虚析构函数。对象在析构时,先调用派生类的析构函数后,再调用基类的析构函数,从而保证所有申请的资源都被释放。</p><h2 id="explicit"><a href="#explicit" class="headerlink" title="explicit"></a>explicit</h2><ol><li>指定构造函数或转换函数 (C++11 起)或推导指引 (C++17 起)为显式,即它不能用于隐式转换和复制初始化。</li><li>explicit 说明符可以与常量表达式一同使用。函数在且只会在该常量表达式求值为 true 时是显式的。(C++20 起)</li></ol><h2 id="decltype"><a href="#decltype" class="headerlink" title="decltype"></a>decltype</h2><p>推导表达式类型:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs c++"><span class="hljs-type">int</span> i = <span class="hljs-number">4</span>;<br><span class="hljs-keyword">decltype</span>(i) a; <span class="hljs-comment">// 推导结果为 int,故 a 的类型为 int</span><br></code></pre></td></tr></table></figure><p>与<code>using</code>和<code>typedef</code>配合使用,用于定义类型:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">using</span> <span class="hljs-type">size_t</span> = <span class="hljs-keyword">decltype</span>(<span class="hljs-built_in">sizeof</span>(<span class="hljs-number">0</span>)); <span class="hljs-comment">// sizeof(a) 的返回值为 size_t 类型</span><br><span class="hljs-keyword">using</span> <span class="hljs-type">ptrdiff_t</span> = <span class="hljs-keyword">decltype</span>((<span class="hljs-type">int</span> *)<span class="hljs-number">0</span> - (<span class="hljs-type">int</span> *)<span class="hljs-number">0</span>);<br><span class="hljs-keyword">using</span> <span class="hljs-type">nullptr_t</span> = <span class="hljs-keyword">decltype</span>(<span class="hljs-literal">nullptr</span>);<br></code></pre></td></tr></table></figure><p>重用匿名类型:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">decltype</span>(anon_s) as ; <span class="hljs-comment">// 定义了一个上面匿名的结构体</span><br></code></pre></td></tr></table></figure><p>泛型编程中结合 auto,用于追踪函数的返回值类型:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">template</span> <<span class="hljs-keyword">typename</span> _Tx, <span class="hljs-keyword">typename</span> _Ty><br><span class="hljs-function"><span class="hljs-keyword">auto</span> <span class="hljs-title">multiply</span><span class="hljs-params">(_Tx x, _Ty y)</span>-><span class="hljs-title">decltype</span><span class="hljs-params">(_Tx*_Ty)</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">return</span> x*y;<br>}<br></code></pre></td></tr></table></figure><h2 id="template"><a href="#template" class="headerlink" title="template"></a>template</h2><p>函数模板,类模板。</p><p>特化与偏特化:模板特殊化和部分特殊化。</p><ol><li>函数模板只有特化,没有偏特化;</li><li>模板、模板的特化和模板的偏特化都存在的情况下,编译器在编译阶段进行匹配,优先特殊的;</li><li>模板函数不能是虚函数;因为每个包含虚函数的类具有一个 virtual table,包含该类的所有虚函数的地址,因此 vtable 的大小是确定的。模板只有被使用时才会被实例化,将其声明为虚函数会使 vtable 的大小不确定。所以,成员函数模板不能为虚函数。</li></ol><h2 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h2><ul><li><a href="https://blog.csdn.net/qq_35429629/article/details/104977738">C++ 中为什么需要将基类的析构函数设置为虚函数?</a></li><li><a href="https://www.cnblogs.com/zhxy/p/3147411.html">inline 函数和宏定义的区别</a></li><li><a href="https://blog.csdn.net/wangliang888888/article/details/77990650">inline 函数和宏定义区别</a></li><li><a href="https://zhuanlan.zhihu.com/p/346400616">C++ 模板 全特化与偏特化</a></li><li><a href="https://zh.cppreference.com/w/cpp/language/explicit">explicit 说明符</a></li></ul>]]></content>
<categories>
<category>cpp</category>
</categories>
<tags>
<tag>CPP</tag>
</tags>
</entry>
<entry>
<title>C++ operator</title>
<link href="/cpp/operator/"/>
<url>/cpp/operator/</url>
<content type="html"><![CDATA[<h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><h2 id="operator"><a href="#operator" class="headerlink" title="operator[]"></a>operator[]</h2><h2 id="operator-1"><a href="#operator-1" class="headerlink" title="operator="></a>operator=</h2><p>复制赋值运算符:<code>ThreadPool &operator=(const ThreadPool &);</code><br>移动赋值运算符:<code>ThreadPool &operator=(ThreadPool &&);</code></p><h2 id="operator-2"><a href="#operator-2" class="headerlink" title="operator=="></a>operator==</h2><h2 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h2>]]></content>
<categories>
<category>cpp</category>
</categories>
<tags>
<tag>CPP</tag>
</tags>
</entry>
<entry>
<title>C++ namespace</title>
<link href="/cpp/namespace/"/>
<url>/cpp/namespace/</url>
<content type="html"><![CDATA[<h2 id="命名空间"><a href="#命名空间" class="headerlink" title="命名空间"></a>命名空间</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><vector></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdlib.h></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdlib.h></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><string.h></span></span><br><br><span class="hljs-keyword">namespace</span> m_nsp<br>{<br> <span class="hljs-keyword">struct</span> <span class="hljs-title class_">_SubData</span><br> {<br> <span class="hljs-type">int</span> a;<br> <span class="hljs-type">int</span> b;<br> };<br><br> <span class="hljs-keyword">using</span> SubData = _SubData;<br><br> <span class="hljs-keyword">typedef</span> <span class="hljs-keyword">struct</span> <span class="hljs-title class_">_MainData</span><br> {<br> SubData s;<br> } MainData;<br>}<br><br><span class="hljs-keyword">using</span> MainData_ = m_nsp::MainData;<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-type">int</span> argc, <span class="hljs-type">char</span> *argv[])</span></span><br><span class="hljs-function"></span>{<br> std::cout << <span class="hljs-string">"Hello, world!\n"</span>;<br><br> MainData_ a;<br><br> FILE *fp = <span class="hljs-built_in">fopen</span>(<span class="hljs-string">"version"</span>, <span class="hljs-string">"r"</span>);<br> <span class="hljs-keyword">if</span> (!fp)<br> {<br> <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;<br> }<br> <span class="hljs-type">char</span> buff[<span class="hljs-number">8</span>] = {<span class="hljs-string">'\0'</span>};<br> <span class="hljs-type">int</span> version;<br> <span class="hljs-built_in">fread</span>(buff, <span class="hljs-built_in">sizeof</span>(buff), <span class="hljs-number">1</span>, fp);<br> <span class="hljs-type">char</span> *ch = <span class="hljs-built_in">strchr</span>(buff, <span class="hljs-string">'.'</span>);<br> *ch = <span class="hljs-string">'\0'</span>;<br> <span class="hljs-built_in">printf</span>(<span class="hljs-string">"%d %d\n"</span>, <span class="hljs-built_in">atoi</span>(buff), <span class="hljs-built_in">atoi</span>(ch + <span class="hljs-number">1</span>));<br><br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>cpp</category>
</categories>
<tags>
<tag>CPP</tag>
</tags>
</entry>
<entry>
<title>C++ 指针与引用</title>
<link href="/cpp/pointer/"/>
<url>/cpp/pointer/</url>
<content type="html"><![CDATA[<h2 id="1-指针"><a href="#1-指针" class="headerlink" title="1 指针"></a>1 指针</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-type">int</span> x;<br><span class="hljs-type">int</span> &a = x;<br><span class="hljs-type">int</span> *<span class="hljs-type">const</span> b = &x;<br></code></pre></td></tr></table></figure><h2 id="2-引用"><a href="#2-引用" class="headerlink" title="2 引用"></a>2 引用</h2><p>引用更接近 const 指针。</p><h3 id="2-1-左值引用"><a href="#2-1-左值引用" class="headerlink" title="2.1 左值引用"></a>2.1 左值引用</h3><p>左值引用要求右边的值必须能够取地址,如果无法取地址,可以用常引用;<br>使用常引用后,我们只能通过引用来读取数据,无法去修改数据,因为其被<code>const</code>修饰成常量引用了。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-type">int</span> a = <span class="hljs-number">0</span>;<br><span class="hljs-type">int</span> &b = a; <span class="hljs-comment">// 左值引用</span><br><span class="hljs-type">const</span> <span class="hljs-type">int</span> &c = <span class="hljs-number">0</span>; <span class="hljs-comment">// 常引用,无法被修改</span><br></code></pre></td></tr></table></figure><h3 id="2-2-右值引用"><a href="#2-2-右值引用" class="headerlink" title="2.2 右值引用"></a>2.2 右值引用</h3><p>立即数,函数返回的值等都是右值</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-type">int</span> &&a = <span class="hljs-number">0</span>; <span class="hljs-comment">// 右值引用,可以被修改</span><br></code></pre></td></tr></table></figure><h3 id="2-3-左值引用与右值引用的区别"><a href="#2-3-左值引用与右值引用的区别" class="headerlink" title="2.3 左值引用与右值引用的区别"></a>2.3 左值引用与右值引用的区别</h3><ul><li>可以取地址的,有名字的,非临时的就是左值;</li><li>不能取地址的,没有名字的,临时的就是右值;</li></ul><h3 id="2-4-万能引用"><a href="#2-4-万能引用" class="headerlink" title="2.4 万能引用"></a>2.4 万能引用</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-function"><span class="hljs-keyword">template</span><<span class="hljs-keyword">typename</span> T></span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">f</span><span class="hljs-params">(T &&arg)</span></span>;<br></code></pre></td></tr></table></figure><h2 id="3-指针与引用的区别"><a href="#3-指针与引用的区别" class="headerlink" title="3 指针与引用的区别"></a>3 指针与引用的区别</h2><h2 id="4-参考文献"><a href="#4-参考文献" class="headerlink" title="4 参考文献"></a>4 参考文献</h2><ul><li><a href="https://www.cnblogs.com/dolphin0520/archive/2011/04/03/2004869.html">浅谈 C++ 中指针和引用的区别</a></li><li><a href="https://blog.csdn.net/xiaolewennofollow/article/details/52559306">C++ 11 左值,右值,左值引用,右值引用,std::move, std::forward</a></li><li><a href="https://zhuanlan.zhihu.com/p/97128024">c++ 左值引用与右值引用</a></li><li><a href="https://zhuanlan.zhihu.com/p/88047800">左值引用和右值引用</a></li><li><a href="https://zhuanlan.zhihu.com/p/99524127">现代 C++ 之万能引用、完美转发、引用折叠</a></li></ul>]]></content>
<categories>
<category>cpp</category>
</categories>
<tags>
<tag>CPP</tag>
</tags>
</entry>
<entry>
<title>C++ Standard Template Library</title>
<link href="/cpp/stl/"/>
<url>/cpp/stl/</url>
<content type="html"><![CDATA[<!--- [1 容器](#1-容器) - [std::array](#stdarray) - [std::vector](#stdvector) - [std::string](#stdstring) - [std::deque](#stddeque) - [std::list](#stdlist) - [std::unordered\_map](#stdunordered_map) - [std::map](#stdmap) - [std::set](#stdset) - [std::pair](#stdpair) - [std::make\_pair](#stdmake_pair)- [2 智能指针](#2-智能指针) - [std::auto\_ptr](#stdauto_ptr) - [std::unique\_ptr](#stdunique_ptr) - [std::shared\_ptr](#stdshared_ptr) - [std::weak\_ptr](#stdweak_ptr) - [std::make\_shared](#stdmake_shared) - [std::make\_unique](#stdmake_unique)- [3 多线程](#3-多线程) - [std::thread](#stdthread) - [std::mutex](#stdmutex) - [std::timed\_mutex](#stdtimed_mutex) - [std::recursive\_mutex](#stdrecursive_mutex) - [std::recursive\_timed\_mutex](#stdrecursive_timed_mutex) - [std::shared\_timed\_mutex](#stdshared_timed_mutex) - [std::shared\_mutex](#stdshared_mutex) - [std::lock\_guard](#stdlock_guard) - [std::unique\_lock](#stdunique_lock) - [std::shared\_lock](#stdshared_lock) - [std::scoped\_lock](#stdscoped_lock) - [std::condition\_variable](#stdcondition_variable) - [std::async](#stdasync)- [4 算法](#4-算法) - [std::find\_if](#stdfind_if) - [std::any\_of](#stdany_of) - [std::transform](#stdtransform) - [std::move](#stdmove) - [std::forward](#stdforward)- [5 文件流](#5-文件流) - [std::fstream](#stdfstream) - [std::ifstream](#stdifstream) - [std::ofstream](#stdofstream)- [6 其它](#6-其它) - [std::chrono](#stdchrono)- [7 参考文献](#7-参考文献)--><h2 id="1-容器"><a href="#1-容器" class="headerlink" title="1 容器"></a>1 容器</h2><h3 id="std-array"><a href="#std-array" class="headerlink" title="std::array"></a>std::array</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><array></span></span><br>std::array<<span class="hljs-type">int</span>, 10> arr = {<span class="hljs-number">0</span>};<br></code></pre></td></tr></table></figure><p>大小固定的数组,支持快速随机访问,不能添加和删除元素。</p><h3 id="std-vector"><a href="#std-vector" class="headerlink" title="std::vector"></a>std::vector</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><vector></span></span><br></code></pre></td></tr></table></figure><p>动态数组(Dynamic Arrays),支持快速随机访问,在尾部之外的位置插入或删除元素可能很慢。</p><p>当需要增加数据时,重新分配一块内存,将原来的数据拷贝过来并加上需要添加的数据,然后删除原来的数据。</p><p>问题:拷贝很耗时。</p><p>优化方案一:提前预留空间,减少分配内存拷贝数据次数。</p><p>优化方案二:使用<code>emplace_back</code>而不是<code>push_back</code>。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs cpp">std::vector<<span class="hljs-type">int</span>> vec;<br>vec.<span class="hljs-built_in">emplace_back</span>(<span class="hljs-number">0</span>);<br>vec.<span class="hljs-built_in">at</span>(<span class="hljs-number">0</span>); <span class="hljs-comment">// Valid</span><br>vec.<span class="hljs-built_in">at</span>(<span class="hljs-number">1</span>); <span class="hljs-comment">// Invalid, terminate called after throwing an instance of 'std::out_of_range'</span><br></code></pre></td></tr></table></figure><h3 id="std-string"><a href="#std-string" class="headerlink" title="std::string"></a>std::string</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><string></span></span><br></code></pre></td></tr></table></figure><p>与 <a href="#std-vector">std::vector</a> 相似,专门用于保存字符,随机访问快,在尾部插入或删除速度快。</p><h3 id="std-deque"><a href="#std-deque" class="headerlink" title="std::deque"></a>std::deque</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><deque></span></span><br></code></pre></td></tr></table></figure><p>双端队列,支持快速随机访问,在头尾位置插入或删除速度很快。</p><h3 id="std-list"><a href="#std-list" class="headerlink" title="std::list"></a>std::list</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><list></span></span><br></code></pre></td></tr></table></figure><p>双向链表,只支持双向顺序访问,速度较慢,在任何位置插入或删除速度都很快。</p><p>前面在讲 STL list 容器时提到,该容器的底层是用双向链表实现的,甚至一些 STL 版本中(比如 SGI STL),list 容器的底层实现使用的是双向循环链表。</p><h3 id="std-unordered-map"><a href="#std-unordered-map" class="headerlink" title="std::unordered_map"></a>std::unordered_map</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><unordered_map></span></span><br></code></pre></td></tr></table></figure><p>底层实现为哈希表,元素无序,查找时间复杂度为 $O(1)$</p><h3 id="std-map"><a href="#std-map" class="headerlink" title="std::map"></a>std::map</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><map></span></span><br></code></pre></td></tr></table></figure><p>底层实现为红黑树,元素有序,查找时间复杂度为 $O(log_{2}{n})$</p><ol><li>容器中的元素是键值对 (key, value),关键字 (key) 起到索引的作用,值 (value) 则表示与索引相关联的数据;</li><li>迭代器不是 const 的,允许修改元素的 value,但不允许修改 key;</li><li>支持下标操作。</li></ol><p>插入重复元素时,如果用<code>insert</code>,则插入失败,如果用操作符,则覆盖已有元素。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-comment">// 插入值的三种方式</span><br>map[key] = value;<br>map.<span class="hljs-built_in">insert</span>(<span class="hljs-built_in">pair</span><key_type, value_type>(key, value));<br>map.<span class="hljs-built_in">insert</span>(map<key_type, value_type>::<span class="hljs-built_in">value_type</span> (key, value));<br></code></pre></td></tr></table></figure><p>获取不存在的元素时,如果用<code>at</code>,会抛出<code>std::out_of_range</code>错误,如果用操作符,会创建对应的元素。正常情况下,建议用<code>at</code>获取元素。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-comment">// 读取数据</span><br><span class="hljs-keyword">if</span> (map.<span class="hljs-built_in">find</span>(key) != map.<span class="hljs-built_in">end</span>()) {<br> value = map.<span class="hljs-built_in">at</span>(key);<br>}<br></code></pre></td></tr></table></figure><h3 id="std-set"><a href="#std-set" class="headerlink" title="std::set"></a>std::set</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><set></span></span><br></code></pre></td></tr></table></figure><p>底层实现为红黑树,元素有序,查找时间复杂度为 $O(log_{2}{n})$</p><ol><li>容器中的元素为关键字 key 的简单集合,每个元素只包含一个关键字;</li><li>迭代器是 const 的,不允许修改元素的值;</li><li>不支持下标操作。</li></ol><p><a href="#std-map">std::map</a> 和 <a href="#std-set">std::set</a> 是根据关键字排序来保证其有序性的,如果允许修改 key 的话,那么首先需要删除该键,然后调节平衡,再插入修改后的键值,调节平衡,如此一来,严重破坏了容器的结构,导致 iterator 失效,不知道应该指向改变前的位置,还是指向改变后的位置。所以 STL 中将 set 的迭代器设置成 const,不允许修改迭代器的值;而 map 的迭代器则不允许修改 key 值,允许修改 value 值。</p><h3 id="std-pair"><a href="#std-pair" class="headerlink" title="std::pair"></a>std::pair</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><utility></span></span><br></code></pre></td></tr></table></figure><h3 id="std-make-pair"><a href="#std-make-pair" class="headerlink" title="std::make_pair"></a>std::make_pair</h3><h2 id="2-智能指针"><a href="#2-智能指针" class="headerlink" title="2 智能指针"></a>2 智能指针</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><memory></span></span><br></code></pre></td></tr></table></figure><h3 id="std-auto-ptr"><a href="#std-auto-ptr" class="headerlink" title="std::auto_ptr"></a>std::auto_ptr</h3><p>Since C++98, deprecated in C++11, removed in C++17.</p><h3 id="std-unique-ptr"><a href="#std-unique-ptr" class="headerlink" title="std::unique_ptr"></a>std::unique_ptr</h3><p>由 C++11 引入,旨在替代不安全的 <a href="#std-auto-ptr">std::auto_ptr</a>。</p><p><code>unique_ptr</code>不共享它的指针,它无法复制到其他<code>unique_ptr</code>,无法通过值传递到函数,也无法用于需要副本的任何标准模板库 (STL) 算法,只能移动<code>unique_ptr</code>。这意味着,内存资源所有权将转移到另一<code>unique_ptr</code>,并且原始<code>unique_ptr</code>不再拥有此资源。</p><p><code>unique_ptr</code>实现了独享所有权的语义,一个非空的<code>unique_ptr</code>总是拥有它所指向的资源。转移一个<code>unique_ptr</code>将会把所有权也从源指针转移给目标指针(源指针被置空)。拷贝一个<code>unique_ptr</code>将不被允许,因为如果你拷贝一个<code>unique_ptr</code>,那么拷贝结束后,这两个<code>unique_ptr</code>都会指向相同的资源,它们都认为自己拥有这块资源,所以都会企图释放。因此<code>unique_ptr</code>是一个仅能移动 (move_only) 的类型。当指针析构时,它所拥有的资源也被销毁。默认情况下,资源的析构是伴随着调用<code>unique_ptr</code>内部的原始指针的<code>delete</code>操作。</p><table><thead><tr><th>Function</th><th>Description</th></tr></thead><tbody><tr><td><code>operator bool</code></td><td>Return true if the stored pointer is not null.</td></tr><tr><td><code>operator=</code></td><td>Move assignment operator.</td></tr><tr><td><code>operator*</code></td><td>Dereference the stored pointer.</td></tr><tr><td><code>operator-></code></td><td>Return the stored pointer.</td></tr><tr><td><code>get</code></td><td>Return the stored pointer.</td></tr><tr><td><code>reset</code></td><td>The deleter will be invoked if a pointer is already owned.</td></tr><tr><td><code>release</code></td><td>Release ownership of any stored pointer.</td></tr><tr><td><code>swap</code></td><td>Exchange the pointer and deleter with another object.</td></tr><tr><td><code>get_deleter</code></td><td>Return a reference to the stored deleter.</td></tr></tbody></table><p>使用场景:</p><ol><li><p>为动态申请的资源提供异常安全保证,动态申请内存后,保证在抛出异常或提前退出时释放资源</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Func</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-type">int</span> *p = <span class="hljs-keyword">new</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">5</span>);<br><br> <span class="hljs-comment">// ...(可能会抛出异常)return</span><br><br> <span class="hljs-keyword">delete</span> p;<br>}<br><span class="hljs-comment">// 替换为下面的写法</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Func</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-function">unique_ptr<<span class="hljs-type">int</span>> <span class="hljs-title">p</span><span class="hljs-params">(<span class="hljs-keyword">new</span> <span class="hljs-type">int</span>(<span class="hljs-number">5</span>))</span></span>;<br><br> <span class="hljs-comment">// ...(可能会抛出异常)</span><br>}<br></code></pre></td></tr></table></figure></li><li><p>返回函数内动态申请资源的所有权</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-function">unique_ptr<<span class="hljs-type">int</span>> <span class="hljs-title">Func</span><span class="hljs-params">(<span class="hljs-type">int</span> p)</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-function">unique_ptr<<span class="hljs-type">int</span>> <span class="hljs-title">pInt</span><span class="hljs-params">(<span class="hljs-keyword">new</span> <span class="hljs-type">int</span>(p))</span></span>;<br> <span class="hljs-keyword">return</span> pInt; <span class="hljs-comment">// 返回 unique_ptr</span><br>}<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-type">int</span> p = <span class="hljs-number">5</span>;<br> unique_ptr<<span class="hljs-type">int</span>> ret = <span class="hljs-built_in">Func</span>(p);<br> cout << *ret << endl;<br> <span class="hljs-comment">// 函数结束后,自动释放资源</span><br>}<br></code></pre></td></tr></table></figure></li><li><p>在容器中保存指针</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> vector<unique_ptr<<span class="hljs-type">int</span>>> vec;<br> <span class="hljs-function">unique_ptr<<span class="hljs-type">int</span>> <span class="hljs-title">p</span><span class="hljs-params">(<span class="hljs-keyword">new</span> <span class="hljs-type">int</span>(<span class="hljs-number">5</span>))</span></span>;<br> vec.<span class="hljs-built_in">push_back</span>(std::<span class="hljs-built_in">move</span>(p)); <span class="hljs-comment">// 使用移动语义</span><br>}<br></code></pre></td></tr></table></figure></li><li><p>管理动态数组</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-function">unique_ptr<<span class="hljs-type">int</span>[]> <span class="hljs-title">p</span><span class="hljs-params">(<span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[<span class="hljs-number">5</span>] {<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>})</span></span>;<br> p[<span class="hljs-number">0</span>] = <span class="hljs-number">0</span>; <span class="hljs-comment">// 重载了 operator[]</span><br>}<br></code></pre></td></tr></table></figure></li><li><p>作为 auto_ptr 的替代品</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><memory></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdlib.h></span></span><br><span class="hljs-keyword">struct</span> <span class="hljs-title class_">Foo</span><br>{<br> <span class="hljs-built_in">Foo</span>() { std::cout << <span class="hljs-string">"Foo::Foo\n"</span>; }<br> ~<span class="hljs-built_in">Foo</span>() { std::cout << <span class="hljs-string">"Foo::~Foo\n"</span>; }<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">bar</span><span class="hljs-params">()</span> </span>{ std::cout << <span class="hljs-string">"Foo::bar\n"</span>; }<br>};<br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">f</span><span class="hljs-params">(<span class="hljs-type">const</span> Foo &)</span></span><br><span class="hljs-function"></span>{<br> std::cout << <span class="hljs-string">"f(const Foo&)\n"</span>;<br>}<br><span class="hljs-keyword">struct</span> <span class="hljs-title class_">D</span><br>{<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">operator</span><span class="hljs-params">()</span><span class="hljs-params">(Foo* foo)</span></span><br><span class="hljs-function"> </span>{<br> std::cout << <span class="hljs-string">"D operator()"</span> << std::endl;<br> <span class="hljs-keyword">delete</span> foo;<br> }<br>};<br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">TestAutoDestroy</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-comment">//1. 普通的 new 对象。</span><br> std::cout << <span class="hljs-string">"TestDestroy...................."</span> << std::endl;<br> {<br> <span class="hljs-function">std::unique_ptr<Foo> <span class="hljs-title">p1</span><span class="hljs-params">(<span class="hljs-keyword">new</span> Foo)</span></span>;<br> }<br> <span class="hljs-comment">//2. 普通的 new[] 对象。</span><br> {<br> <span class="hljs-function">std::unique_ptr<Foo[]> <span class="hljs-title">p2</span><span class="hljs-params">(<span class="hljs-keyword">new</span> Foo[<span class="hljs-number">4</span>])</span></span>;<br> }<br> <span class="hljs-comment">//3. 自定义的 deleter.</span><br> {<br> <span class="hljs-function">std::unique_ptr<Foo, D> <span class="hljs-title">p3</span><span class="hljs-params">(<span class="hljs-keyword">new</span> Foo)</span></span>;<br> }<br>}<br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">TestOwner</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> std::cout << <span class="hljs-string">"TestOwner...................."</span> << std::endl;<br> <span class="hljs-comment">//1. new object.</span><br> <span class="hljs-function">std::unique_ptr<Foo> <span class="hljs-title">p1</span><span class="hljs-params">(<span class="hljs-keyword">new</span> Foo)</span></span>; <span class="hljs-comment">// p1 owns Foo</span><br> <span class="hljs-keyword">if</span> (p1) p1-><span class="hljs-built_in">bar</span>();<br> {<br> <span class="hljs-function">std::unique_ptr<Foo> <span class="hljs-title">p2</span><span class="hljs-params">(std::move(p1))</span></span>; <span class="hljs-comment">// now p2 owns Foo</span><br> <span class="hljs-built_in">f</span>(*p2);<br> p1 = std::<span class="hljs-built_in">move</span>(p2); <span class="hljs-comment">// ownership returns to p1</span><br> p2-><span class="hljs-built_in">bar</span>();<br> std::cout << <span class="hljs-string">"destroying p2...\n"</span>;<br> }<br> p1-><span class="hljs-built_in">bar</span>();<br>}<br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">TestArrayOwner</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> std::cout << <span class="hljs-string">"TestArrayOwner...................."</span> << std::endl;<br> <span class="hljs-comment">//1. new[] object.</span><br> <span class="hljs-function">std::unique_ptr<Foo[]> <span class="hljs-title">p1</span><span class="hljs-params">(<span class="hljs-keyword">new</span> Foo[<span class="hljs-number">4</span>])</span></span>; <span class="hljs-comment">// p1 owns Foo</span><br> <span class="hljs-keyword">if</span> (p1) p1[<span class="hljs-number">0</span>].<span class="hljs-built_in">bar</span>();<br> {<br> <span class="hljs-function">std::unique_ptr<Foo[]> <span class="hljs-title">p2</span><span class="hljs-params">(std::move(p1))</span></span>; <span class="hljs-comment">// now p2 owns Foo</span><br> <span class="hljs-built_in">f</span>(p2[<span class="hljs-number">0</span>]);<br> p1 = std::<span class="hljs-built_in">move</span>(p2); <span class="hljs-comment">// ownership returns to p1</span><br> p2[<span class="hljs-number">0</span>].<span class="hljs-built_in">bar</span>();<br> std::cout << <span class="hljs-string">"destroying p2...\n"</span>;<br> }<br> p1[<span class="hljs-number">0</span>].<span class="hljs-built_in">bar</span>();<br>}<br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-built_in">TestAutoDestroy</span>();<br> <span class="hljs-built_in">TestOwner</span>();<br> <span class="hljs-built_in">TestArrayOwner</span>();<br>}<br></code></pre></td></tr></table></figure><p>输出:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><code class="hljs bash">TestDestroy....................<br>Foo::Foo<br>Foo::~Foo<br>Foo::Foo<br>Foo::Foo<br>Foo::Foo<br>Foo::Foo<br>Foo::~Foo<br>Foo::~Foo<br>Foo::~Foo<br>Foo::~Foo<br>Foo::Foo<br>D operator()<br>Foo::~Foo<br>TestOwner....................<br>Foo::Foo<br>Foo::bar<br>f(const Foo&)<br>Foo::bar<br>destroying p2...<br>Foo::bar<br>Foo::~Foo<br>TestArrayOwner....................<br>Foo::Foo<br>Foo::Foo<br>Foo::Foo<br>Foo::Foo<br>Foo::bar<br>f(const Foo&)<br>Foo::bar<br>destroying p2...<br>Foo::bar<br>Foo::~Foo<br>Foo::~Foo<br>Foo::~Foo<br>Foo::~Foo<br></code></pre></td></tr></table></figure></li></ol><ul><li><a href="https://www.cnblogs.com/DswCnblog/p/5628195.html">C++ 11 创建和使用 unique_ptr</a></li></ul><h3 id="std-shared-ptr"><a href="#std-shared-ptr" class="headerlink" title="std::shared_ptr"></a>std::shared_ptr</h3><p>空的<code>shared_ptr</code>指针,其初始引用计数为 0,而不是 1。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-function">std::shared_ptr<<span class="hljs-type">int</span>> <span class="hljs-title">p3</span><span class="hljs-params">(<span class="hljs-keyword">new</span> <span class="hljs-type">int</span>(<span class="hljs-number">10</span>))</span></span>;<br>std::shared_ptr<<span class="hljs-type">int</span>> p3 = std::<span class="hljs-built_in">make_shared</span><<span class="hljs-type">int</span>>(<span class="hljs-number">10</span>);<br><span class="hljs-function">std::shared_ptr<<span class="hljs-type">int</span>> <span class="hljs-title">p4</span><span class="hljs-params">(p3)</span></span>; <span class="hljs-comment">// Copy Constructor</span><br>std::shared_ptr<<span class="hljs-type">int</span>> p4 = p3; <span class="hljs-comment">// Copy Assignment operator</span><br><span class="hljs-function">std::shared_ptr<<span class="hljs-type">int</span>> <span class="hljs-title">p5</span><span class="hljs-params">(std::move(p4))</span></span>; <span class="hljs-comment">// Move Constructor</span><br>std::shared_ptr<<span class="hljs-type">int</span>> p5 = std::<span class="hljs-built_in">move</span>(p4); <span class="hljs-comment">// Move Assignment operator</span><br></code></pre></td></tr></table></figure><p>如上所示,p3 和 p4 都是 shared_ptr 类型的智能指针,因此可以用 p3 来初始化 p4,由于 p3 是左值,因此会调用拷贝构造函数。需要注意的是,如果 p3 为空智能指针,则 p4 也为空智能指针,其引用计数初始值为 0;反之,则表明 p4 和 p3 指向同一块堆内存,同时该堆空间的引用计数会加 1。</p><p>而对于<code>std::move(p4)</code>来说,该函数会强制将 p4 转换成对应的右值,因此初始化 p5 调用的是移动构造函数。另外和调用拷贝构造函数不同,用<code>std::move(p4)</code>初始化 p5,会使得 p5 拥有了 p4 的堆内存,而 p4 则变成了空智能指针。</p><p>同一普通指针不能同时为多个<code>shared_ptr</code>对象赋值,否则会导致程序发生异常。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-function">std::shared_ptr<<span class="hljs-type">int</span>> <span class="hljs-title">p6</span><span class="hljs-params">(<span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[<span class="hljs-number">10</span>], std::default_delete<<span class="hljs-type">int</span>[]>())</span></span>; <span class="hljs-comment">// 指定 default_delete 作为释放规则</span><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">deleteInt</span><span class="hljs-params">(<span class="hljs-type">int</span>*p)</span> </span>{ <span class="hljs-comment">// 自定义释放规则</span><br> <span class="hljs-keyword">delete</span> []p;<br>}<br><span class="hljs-function">std::shared_ptr<<span class="hljs-type">int</span>> <span class="hljs-title">p7</span><span class="hljs-params">(<span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[<span class="hljs-number">10</span>], deleteInt)</span></span>; <span class="hljs-comment">// 初始化智能指针,并自定义释放规则</span><br><span class="hljs-function">std::shared_ptr<<span class="hljs-type">int</span>> <span class="hljs-title">p7</span><span class="hljs-params">(<span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[<span class="hljs-number">10</span>], [](<span class="hljs-type">int</span>* p) {<span class="hljs-keyword">delete</span>[]p; })</span></span>;<br></code></pre></td></tr></table></figure><table><thead><tr><th>Function</th><th>Description</th></tr></thead><tbody><tr><td><code>operator bool</code></td><td>Return true if the stored pointer is not null.</td></tr><tr><td><code>operator=</code></td><td>Move assignment operator.</td></tr><tr><td><code>operator*</code></td><td>Dereference the stored pointer.</td></tr><tr><td><code>operator-></code></td><td>Return the stored pointer.</td></tr><tr><td><code>get</code></td><td>Return the stored pointer.</td></tr><tr><td><code>swap</code></td><td>交换 2 个相同类型 shared_ptr 智能指针的内容。</td></tr><tr><td><code>reset</code></td><td>形参为空,当前对象重置为空指针;当传入新申请的堆内存时,则获得该存储空间的所有权,引用计数的重置为 1。</td></tr><tr><td><code>use_count</code></td><td>返回引用计数。</td></tr><tr><td><code>unique</code></td><td>判断指向堆内存的 shared_ptr 对象是否唯一。</td></tr></tbody></table><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><memory></span></span><br><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-function">std::shared_ptr<<span class="hljs-type">int</span>> <span class="hljs-title">p1</span><span class="hljs-params">(<span class="hljs-keyword">new</span> <span class="hljs-type">int</span>(<span class="hljs-number">10</span>))</span></span>;<br> <span class="hljs-function">std::shared_ptr<<span class="hljs-type">int</span>> <span class="hljs-title">p2</span><span class="hljs-params">(p1)</span></span>;<br> <span class="hljs-function">std::shared_ptr<<span class="hljs-type">int</span>> <span class="hljs-title">p3</span><span class="hljs-params">(p1)</span></span>;<br><br> <span class="hljs-comment">// p1、p2、p3 指向同一块堆内存,引用基数均为 3</span><br> std::cout << p1.<span class="hljs-built_in">get</span>() << <span class="hljs-string">" "</span> << p2.<span class="hljs-built_in">get</span>() << <span class="hljs-string">" "</span> << p3.<span class="hljs-built_in">get</span>() << std::endl;<br> std::cout << p1.<span class="hljs-built_in">use_count</span>() << <span class="hljs-string">" "</span> << p2.<span class="hljs-built_in">use_count</span>() << <span class="hljs-string">" "</span> << p3.<span class="hljs-built_in">use_count</span>() << std::endl;<br><br> p1.<span class="hljs-built_in">reset</span>(); <span class="hljs-comment">// p1 重置为空指针,p2、p3 指向同一块堆内存,p2、p3 引用计数减 1</span><br> std::cout << p1.<span class="hljs-built_in">get</span>() << <span class="hljs-string">" "</span> << p2.<span class="hljs-built_in">get</span>() << <span class="hljs-string">" "</span> << p3.<span class="hljs-built_in">get</span>() << std::endl;<br> std::cout << p1.<span class="hljs-built_in">use_count</span>() << <span class="hljs-string">" "</span> << p2.<span class="hljs-built_in">use_count</span>() << <span class="hljs-string">" "</span> << p3.<span class="hljs-built_in">use_count</span>() << std::endl;<br><br> p2.<span class="hljs-built_in">reset</span>(<span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[<span class="hljs-number">10</span>]); <span class="hljs-comment">// p2 指向新的堆内存,p2 引用计数重置为 1,p3 引用计数减 1</span><br> std::cout << p1.<span class="hljs-built_in">get</span>() << <span class="hljs-string">" "</span> << p2.<span class="hljs-built_in">get</span>() << <span class="hljs-string">" "</span> << p3.<span class="hljs-built_in">get</span>() << std::endl;<br> std::cout << p1.<span class="hljs-built_in">use_count</span>() << <span class="hljs-string">" "</span> << p2.<span class="hljs-built_in">use_count</span>() << <span class="hljs-string">" "</span> << p3.<span class="hljs-built_in">use_count</span>() << std::endl;<br><br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><ul><li><a href="http://c.biancheng.net/view/7898.html">C++11 shared_ptr 智能指针</a></li></ul><h3 id="std-weak-ptr"><a href="#std-weak-ptr" class="headerlink" title="std::weak_ptr"></a>std::weak_ptr</h3><p><code>shared_ptr</code>是采用引用计数的智能指针,多个<code>shared_ptr</code>实例可以指向同一个动态对象,并维护了一个共享的引用计数器。对于引用计数法实现的计数,总是避免不了循环引用或环形引用的问题,<code>shared_ptr</code>也不例外。</p><p><code>weak_ptr</code>是为了配合<code>shared_ptr</code>而引入的一种智能指针,它指向一个由<code>shared_ptr</code>管理的对象而不影响所指对象的生命周期,也就是将一个<code>weak_ptr</code>绑定到一个<code>shared_ptr</code>不会改变<code>shared_ptr</code>的引用计数。不论是否有<code>weak_ptr</code>指向,一旦最后一个指向对象的<code>shared_ptr</code>被销毁,对象就会被释放。从这个角度看,<code>weak_ptr</code>更像是<code>shared_ptr</code>的一个助手而不是智能指针。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>;<br><span class="hljs-keyword">class</span> <span class="hljs-title class_">B</span>;<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span><br>{<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-built_in">A</span>() { cout << <span class="hljs-string">"A Constructor..."</span> << endl; }<br> ~<span class="hljs-built_in">A</span>() { cout << <span class="hljs-string">"A Destructor..."</span> << endl; }<br> weak_ptr<B> pb; <span class="hljs-comment">// 在 A 中引用 B</span><br> <span class="hljs-comment">// shared_ptr<B> pb;</span><br>};<br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">B</span><br>{<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-built_in">B</span>() { cout << <span class="hljs-string">"B Constructor..."</span> << endl; }<br> ~<span class="hljs-built_in">B</span>() { cout << <span class="hljs-string">"B Destructor..."</span> << endl; }<br> weak_ptr<A> pa; <span class="hljs-comment">// 在 B 中引用 A</span><br> <span class="hljs-comment">// shared_ptr<A> pa;</span><br>};<br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> shared_ptr<A> spa = <span class="hljs-built_in">make_shared</span><A>();<br> shared_ptr<B> spb = <span class="hljs-built_in">make_shared</span><B>();<br> spa->pb = spb;<br> spb->pa = spa;<br>}<br></code></pre></td></tr></table></figure><table><thead><tr><th>Function</th><th>Description</th></tr></thead><tbody><tr><td><code>lock</code></td><td>creates a <code>shared_ptr</code> that manages the referenced object</td></tr></tbody></table><ul><li><a href="https://www.jianshu.com/p/03eea8262c11">C++11 make_shared</a></li><li><a href="https://stackoverflow.com/questions/8147027/how-do-i-call-stdmake-shared-on-a-class-with-only-protected-or-private-const?rq=1">How do I call ::std::make_shared on a class with only protected or private constructors?</a></li><li><a href="https://en.cppreference.com/w/cpp/memory/weak_ptr/lock">std::weak_ptr<T>::lock</a></li></ul><h3 id="std-make-shared"><a href="#std-make-shared" class="headerlink" title="std::make_shared"></a>std::make_shared</h3><p>C++11 引入</p><p><code>make_shared</code>与<code>new</code>的区别:</p><ul><li><p><code>std::shared_ptr<object> ptr = new object()</code><br>由于<code>object</code>是先创建的,那么在将<code>object</code>指针传给<code>shared_ptr</code>时,<code>shared_ptr</code>只能单独分配控制块,如下图:<br><img src="/cpp/stl/images/new.png" alt="new"></p></li><li><p><code>std::shared_ptr<object> ptr = std::make_shared<object>()</code><br><code>object</code>和对应的控制块是同时创建的,如下图:<br><img src="/cpp/stl/images/std_make_shared.png" alt="std::make_shared"></p></li><li><p><a href="https://www.jianshu.com/p/03eea8262c11">C++11 make_shared</a></p></li></ul><h3 id="std-make-unique"><a href="#std-make-unique" class="headerlink" title="std::make_unique"></a>std::make_unique</h3><p>C++14 引入</p><h2 id="3-多线程"><a href="#3-多线程" class="headerlink" title="3 多线程"></a>3 多线程</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><mutex></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><condition_variable></span></span><br></code></pre></td></tr></table></figure><h3 id="std-thread"><a href="#std-thread" class="headerlink" title="std::thread"></a>std::thread</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><thread></span></span><br></code></pre></td></tr></table></figure><h3 id="std-mutex"><a href="#std-mutex" class="headerlink" title="std::mutex"></a>std::mutex</h3><p>基本的互斥量。同一线程<code>lock</code>多次会造成未定义的行为,不同线程<code>lock</code>会阻塞,我们使用阻塞的特性。</p><h3 id="std-timed-mutex"><a href="#std-timed-mutex" class="headerlink" title="std::timed_mutex"></a>std::timed_mutex</h3><p>有超时机制的互斥量</p><h3 id="std-recursive-mutex"><a href="#std-recursive-mutex" class="headerlink" title="std::recursive_mutex"></a>std::recursive_mutex</h3><p>可重入的互斥量</p><h3 id="std-recursive-timed-mutex"><a href="#std-recursive-timed-mutex" class="headerlink" title="std::recursive_timed_mutex"></a>std::recursive_timed_mutex</h3><p>结合<code>timed_mutex</code>和<code>recursive_mutex</code>特点的互斥量</p><h3 id="std-shared-timed-mutex"><a href="#std-shared-timed-mutex" class="headerlink" title="std::shared_timed_mutex"></a>std::shared_timed_mutex</h3><p>具有超时机制的可共享互斥量</p><h3 id="std-shared-mutex"><a href="#std-shared-mutex" class="headerlink" title="std::shared_mutex"></a>std::shared_mutex</h3><p>共享的互斥量。底层实现是操作系统提供的读写锁。</p><ul><li><code>lock</code>和<code>unlock</code>分别用于获取写锁和解除写锁。</li><li><code>lock_shared</code>和<code>unlock_shared</code>分别用于获取读锁和解除读锁。</li></ul><p>我们一般将写锁模式称为排他锁 (Exclusive Locking),将读锁模式称为共享锁 (Shared Locking)。</p><h3 id="std-lock-guard"><a href="#std-lock-guard" class="headerlink" title="std::lock_guard"></a>std::lock_guard</h3><p>基于作用域的互斥量管理,构造加锁,析构解锁。</p><h3 id="std-unique-lock"><a href="#std-unique-lock" class="headerlink" title="std::unique_lock"></a>std::unique_lock</h3><p>独占互斥量管理,C++11 引入。</p><p>通常与<code>shared_mutex</code>配合使用,此对象构造时自动对<code>shared_mutex</code>加写锁,析构时自动对<code>shared_mutex</code>解写锁。</p><h3 id="std-shared-lock"><a href="#std-shared-lock" class="headerlink" title="std::shared_lock"></a>std::shared_lock</h3><p>共享互斥量管理,C++14 引入。</p><p>通常与<code>shared_mutex</code>配合使用,此对象构造时自动对<code>shared_mutex</code>加读锁,析构时自动对<code>shared_mutex</code>解读锁。</p><h3 id="std-scoped-lock"><a href="#std-scoped-lock" class="headerlink" title="std::scoped_lock"></a>std::scoped_lock</h3><p>多互斥量避免死锁的管理</p><h3 id="std-condition-variable"><a href="#std-condition-variable" class="headerlink" title="std::condition_variable"></a>std::condition_variable</h3><p>使用此对象时,需要绑定一个<code>lock_guard</code>或<code>unique_lock</code>对象。</p><ul><li><code>wait</code> <code>wait_for</code> <code>wait_until</code> 该操作能够原子性的释放互斥量<code>mutex</code>上的锁,并阻塞这个线程,当被通知后,解除当前阻塞线程,恢复互斥量<code>mutex</code>上的锁。</li><li><code>notify_one</code> <code>notify_all</code> 在持有锁的期间去唤醒阻塞线程。</li></ul><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs cpp">std::condition_variable cv;<br>std::mutex m;<br><span class="hljs-comment">/* A thread */</span><br><span class="hljs-function">std::unique_lock<std::mutex> <span class="hljs-title">lock</span><span class="hljs-params">(m)</span></span>;<br>cv.<span class="hljs-built_in">wait</span>(m); <span class="hljs-comment">// 解锁 m,阻塞等待</span><br><span class="hljs-comment">/* B thread */</span><br>cv.<span class="hljs-built_in">notify_one</span>(); <span class="hljs-comment">// A thread 解除等待</span><br></code></pre></td></tr></table></figure><h3 id="std-async"><a href="#std-async" class="headerlink" title="std::async"></a>std::async</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><future></span></span><br></code></pre></td></tr></table></figure><p>Since C++11</p><h2 id="4-算法"><a href="#4-算法" class="headerlink" title="4 算法"></a>4 算法</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><algorithm></span></span><br></code></pre></td></tr></table></figure><h3 id="std-find-if"><a href="#std-find-if" class="headerlink" title="std::find_if"></a>std::find_if</h3><h3 id="std-any-of"><a href="#std-any-of" class="headerlink" title="std::any_of"></a>std::any_of</h3><h3 id="std-transform"><a href="#std-transform" class="headerlink" title="std::transform"></a>std::transform</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><algorithm></span></span><br></code></pre></td></tr></table></figure><h3 id="std-move"><a href="#std-move" class="headerlink" title="std::move"></a>std::move</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><utility></span></span><br></code></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * @brief Convert a value to an rvalue.</span><br><span class="hljs-comment"> * @param __t A thing of arbitrary type.</span><br><span class="hljs-comment"> * @return The parameter cast to an rvalue-reference to allow moving it.</span><br><span class="hljs-comment">*/</span><br><span class="hljs-keyword">template</span><<span class="hljs-keyword">typename</span> _Tp><br><span class="hljs-keyword">constexpr</span> <span class="hljs-keyword">typename</span> std::remove_reference<_Tp>::<span class="hljs-function">type&& <span class="hljs-title">move</span><span class="hljs-params">(_Tp&& <span class="hljs-type">__t</span>)</span> <span class="hljs-keyword">noexcept</span> </span>{<br> <span class="hljs-keyword">return</span> <span class="hljs-keyword">static_cast</span><<span class="hljs-keyword">typename</span> std::remove_reference<_Tp>::type&&>(<span class="hljs-type">__t</span>);<br>}<br></code></pre></td></tr></table></figure><ul><li>C++ 标准库使用比如<code>vector::push_back</code>等这类函数时,会对参数的对象进行复制,连数据也会复制。这就会造成对象内存的额外创建,本来原意是想把参数<code>push_back</code>进去就行了,通过<code>std::move</code>,可以避免不必要的拷贝操作。</li><li><code>std::move</code>是将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存的搬迁或者内存拷贝,所以可以提高利用效率,改善性能.。</li><li>对指针类型的标准库对象并不需要这么做。</li></ul><h3 id="std-forward"><a href="#std-forward" class="headerlink" title="std::forward"></a>std::forward</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-function"><span class="hljs-keyword">template</span><<span class="hljs-keyword">class</span> T></span><br><span class="hljs-function"><span class="hljs-keyword">constexpr</span> T&& <span class="hljs-title">forward</span><span class="hljs-params">(std::<span class="hljs-type">remove_reference_t</span><T>& arg)</span> <span class="hljs-keyword">noexcept</span> </span>{<br> <span class="hljs-comment">// forward an lvalue as either an lvalue or an rvalue</span><br> <span class="hljs-keyword">return</span> (<span class="hljs-built_in">static_cast</span><T&&>(arg));<br>}<br><span class="hljs-function"><span class="hljs-keyword">template</span><<span class="hljs-keyword">class</span> T></span><br><span class="hljs-function"><span class="hljs-keyword">constexpr</span> T&& <span class="hljs-title">forward</span><span class="hljs-params">(std::<span class="hljs-type">remove_reference_t</span><T>&& arg)</span> <span class="hljs-keyword">noexcept</span> </span>{<br> <span class="hljs-comment">// forward an rvalue as an rvalue</span><br> <span class="hljs-keyword">return</span> (<span class="hljs-built_in">static_cast</span><T&&>(arg));<br>}<br></code></pre></td></tr></table></figure><p><code>forward</code>通常是用于完美转发的,它会将输入的参数原封不动地传递到下一个函数中,这个“原封不动”指的是,如果输入的参数是左值,那么传递给下一个函数的参数的也是左值;如果输入的参数是右值,那么传递给下一个函数的参数的也是右值。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">template</span> <<span class="hljs-keyword">class</span>... Args><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">forward</span><span class="hljs-params">(Args&&... args)</span> </span>{<br> <span class="hljs-built_in">f</span>(std::forward<Args>(args)...);<br>}<br></code></pre></td></tr></table></figure><p>引用折叠:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs cpp">&& && -> &&<br>& && -> &<br>& & -> &<br>&& & -> &<br></code></pre></td></tr></table></figure><h2 id="5-文件流"><a href="#5-文件流" class="headerlink" title="5 文件流"></a>5 文件流</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><fstream></span></span><br></code></pre></td></tr></table></figure><table><thead><tr><th>Flag</th><th>Description</th></tr></thead><tbody><tr><td><code>std::ios::app</code></td><td>append</td></tr><tr><td><code>std::ios::ate</code></td><td>at end</td></tr><tr><td><code>std::ios::in</code></td><td>read</td></tr><tr><td><code>std::ios::out</code></td><td>write</td></tr><tr><td><code>std::ios::trunc</code></td><td>clear</td></tr></tbody></table><h3 id="std-fstream"><a href="#std-fstream" class="headerlink" title="std::fstream"></a>std::fstream</h3><p>该数据类型通常表示文件流,且同时具有<code>ofstream</code>和<code>ifstream</code>两种功能,这意味着它可以创建文件,向文件写入信息,从文件读取信息。</p><h3 id="std-ifstream"><a href="#std-ifstream" class="headerlink" title="std::ifstream"></a>std::ifstream</h3><p>该数据类型表示输入文件流,用于从文件读取信息。</p><h3 id="std-ofstream"><a href="#std-ofstream" class="headerlink" title="std::ofstream"></a>std::ofstream</h3><p>该数据类型表示输出文件流,用于创建文件并向文件写入信息。</p><h2 id="6-其它"><a href="#6-其它" class="headerlink" title="6 其它"></a>6 其它</h2><h3 id="std-chrono"><a href="#std-chrono" class="headerlink" title="std::chrono"></a>std::chrono</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><chrono></span></span><br><span class="hljs-keyword">struct</span> <span class="hljs-title class_">Timer</span><br>{<br> std::chrono::system_clock::time_point start, end;<br> std::chrono::duration<<span class="hljs-type">float</span>> duration;<br><br> <span class="hljs-built_in">Timer</span>()<br> {<br> start = std::chrono::high_resolution_clock::<span class="hljs-built_in">now</span>();<br> }<br> ~<span class="hljs-built_in">Timer</span>()<br> {<br> end = std::chrono::high_resolution_clock::<span class="hljs-built_in">now</span>();<br> duration = end - start;<br> <span class="hljs-type">const</span> <span class="hljs-type">float</span> seconds = duration.<span class="hljs-built_in">count</span>();<br> <span class="hljs-keyword">if</span> (seconds < <span class="hljs-number">1</span>) {<br> std::cout << <span class="hljs-string">"Timer took "</span> << seconds * <span class="hljs-number">1000.0f</span> << <span class="hljs-string">"ms"</span> << std::endl;<br> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (seconds < <span class="hljs-number">60</span>) {<br> std::cout << <span class="hljs-string">"Timer took "</span> << seconds << <span class="hljs-string">"s"</span> << std::endl;<br> } <span class="hljs-keyword">else</span> {<br> std::cout << <span class="hljs-string">"Timer took "</span> << seconds / <span class="hljs-number">60</span> << <span class="hljs-string">"min"</span> << std::endl;<br> }<br> }<br>};<br></code></pre></td></tr></table></figure><p>可用于统计程序运行的时间。</p><h2 id="7-参考文献"><a href="#7-参考文献" class="headerlink" title="7 参考文献"></a>7 参考文献</h2><ul><li><a href="http://c.biancheng.net/stl/stl_basic/">C++ STL 标准库基础</a></li><li><a href="https://www.cnblogs.com/WindSun/p/11444429.html">详解 C++11 智能指针</a></li><li><a href="https://blog.csdn.net/batuwuhanpei/article/details/50727227">C++ 中 map 与 unordered_map 的区别</a></li><li><a href="https://blog.csdn.net/zhoucheng05_13/article/details/81013684">C++ Map 相同 key 是否覆盖问题分析</a></li><li><a href="https://zhuanlan.zhihu.com/p/92486757">浅谈 std::forward</a></li><li><a href="https://ppipp.blog.csdn.net/article/details/84644069?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~Rate-1.pc_relevant_antiscanv2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~Rate-1.pc_relevant_antiscanv2&utm_relevant_index=2">c++ 之 std::move 原理实现与用法总结</a></li><li><a href="https://blog.csdn.net/fengbingchun/article/details/63252470?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~Rate-1.pc_relevant_paycolumn_v3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~Rate-1.pc_relevant_paycolumn_v3&utm_relevant_index=2">C++/C++11 中 std::transform 的使用</a></li><li><a href="https://segmentfault.com/a/1190000039083151">std::async 的使用总结</a></li></ul>]]></content>
<categories>
<category>cpp</category>
</categories>
<tags>
<tag>CPP</tag>
</tags>
</entry>
<entry>
<title>Hexo</title>
<link href="/blog/hexo/"/>
<url>/blog/hexo/</url>
<content type="html"><![CDATA[<!--- [概述](#概述)- [主题](#主题) - [Fluid](#fluid) - [Next](#next)- [配置环境](#配置环境)- [参考文献](#参考文献)--><h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><p><a href="https://hexo.io/">https://hexo.io</a></p><h2 id="主题"><a href="#主题" class="headerlink" title="主题"></a>主题</h2><h3 id="Fluid"><a href="#Fluid" class="headerlink" title="Fluid"></a>Fluid</h3><p><a href="https://github.com/fluid-dev/hexo-theme-fluid">https://github.com/fluid-dev/hexo-theme-fluid</a><br><a href="https://hexo.fluid-dev.com/">https://hexo.fluid-dev.com/</a></p><h3 id="Next"><a href="#Next" class="headerlink" title="Next"></a>Next</h3><p><a href="https://github.com/iissnan/hexo-theme-next">https://github.com/iissnan/hexo-theme-next</a><br><a href="https://notes.iissnan.com/">https://notes.iissnan.com/</a></p><h2 id="配置环境"><a href="#配置环境" class="headerlink" title="配置环境"></a>配置环境</h2><p>方法一:在宿主机中配置<code>nodejs</code>环境</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">mkdir</span> hexo && <span class="hljs-built_in">cd</span> hexo<br>hexo init . && npm install hexo-cli -g<br></code></pre></td></tr></table></figure><p>方法二:基于<code>node</code>构建<code>hexo</code>镜像</p><ol><li><p>创建 Dockerfile</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">FROM</span> node:latest<br><span class="hljs-keyword">WORKDIR</span><span class="language-bash"> /var/www/hexo</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> <span class="hljs-built_in">echo</span> <span class="hljs-string">"Asia/Shanghai"</span> > /etc/timezone \</span><br><span class="language-bash"> && <span class="hljs-built_in">rm</span> /etc/localtime && <span class="hljs-built_in">ln</span> -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> apt-get update && apt-get -y install cron git \</span><br><span class="language-bash"> && git config --global init.defaultBranch main \</span><br><span class="language-bash"> && git config --global user.name <span class="hljs-string">"xxx"</span> \</span><br><span class="language-bash"> && git config --global user.email <span class="hljs-string">"[email protected]"</span></span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> npm install npm hexo-cli -g</span><br><span class="hljs-keyword">CMD</span><span class="language-bash"> [<span class="hljs-string">"/bin/bash"</span>, <span class="hljs-string">"-c"</span>, <span class="hljs-string">"hexo clean && hexo generate && hexo server"</span>]</span><br></code></pre></td></tr></table></figure></li><li><p>创建镜像</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker build -t hexo .<br></code></pre></td></tr></table></figure></li><li><p>启动镜像</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker stop hexo<br>docker <span class="hljs-built_in">rm</span> hexo<br>docker run \<br> --detach \<br> --<span class="hljs-built_in">tty</span> \<br> --interactive \<br> --name hexo \<br> --hostname=hexo \<br> --publish 80:4000 \<br> --restart unless-stopped \<br> --volume /home/hexo:/var/www/hexo \<br> hexo<br></code></pre></td></tr></table></figure></li><li><p>进入镜像<code>docker exec -it hexo bash</code></p></li><li><p>更新模块<code>npm update</code></p></li><li><p>部署站点<code>hexo generate --deploy</code>或者<code>hexo deploy --generate</code></p></li></ol><p>常用命令:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs bash">hexo init . <span class="hljs-comment"># 初始化</span><br>npm install <span class="hljs-comment"># 安装包</span><br>npm update <span class="hljs-comment"># 更新包</span><br>hexo clean <span class="hljs-comment"># 清理缓存</span><br>hexo generate <span class="hljs-comment"># 更新页面</span><br>hexo server <span class="hljs-comment"># 启动服务</span><br></code></pre></td></tr></table></figure><h2 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h2><ul><li><a href="https://hexo.io/zh-cn/docs/">hexo.io</a></li></ul>]]></content>
<categories>
<category>blog</category>
</categories>
<tags>
<tag>Docker</tag>
<tag>Hexo</tag>
</tags>
</entry>
<entry>
<title>Docker</title>
<link href="/tools/docker/"/>
<url>/tools/docker/</url>
<content type="html"><![CDATA[<h2 id="配置环境"><a href="#配置环境" class="headerlink" title="配置环境"></a>配置环境</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 安装 Docker</span><br>sudo apt install docker-ce<br>sudo apt install docker.io <span class="hljs-comment"># debian</span><br><span class="hljs-comment"># 不用 sudo 使用 docker (可选)</span><br>sudo groupadd docker<br>sudo usermod -aG docker <span class="hljs-variable">$USER</span> <span class="hljs-comment"># 将当前用户添加至 docker 组</span><br>newgrp docker <span class="hljs-comment"># 使修改生效</span><br><span class="hljs-comment"># 配置 image 仓库</span><br><span class="hljs-comment"># echo DOCKER_OPTS="--registry-mirror=https://registry.docker-cn.com" >> /etc/default/docker</span><br>docker run hello-world <span class="hljs-comment"># 测试</span><br><span class="hljs-comment"># 配置 docker 自启</span><br>sudo systemctl <span class="hljs-built_in">enable</span> docker.service<br>sudo systemctl <span class="hljs-built_in">enable</span> containerd.service<br><span class="hljs-comment"># 修改 docker images 存储目录</span><br>docker info <span class="hljs-comment"># Docker Root Dir: /var/lib/docker</span><br>sudo vim /etc/docker/daemon.json <span class="hljs-comment"># 没有就创建</span><br>{<br> <span class="hljs-string">"data-root"</span>: <span class="hljs-string">"/home/docker"</span><br>}<br>sudo systemctl restart docker.service<br>sudo <span class="hljs-built_in">mv</span> /var/lib/docker /home/docker<br></code></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># nvidia 显卡支持</span><br>distribution=$(. /etc/os-release;<span class="hljs-built_in">echo</span> $ID<span class="hljs-variable">$VERSION_ID</span>) \<br> && curl -s -L https://nvidia.github.io/libnvidia-container/gpgkey | sudo apt-key add - \<br> && curl -s -L https://nvidia.github.io/libnvidia-container/<span class="hljs-variable">$distribution</span>/libnvidia-container.list | sudo <span class="hljs-built_in">tee</span> /etc/apt/sources.list.d/nvidia-container-toolkit.list<br>sudo apt-get install -y nvidia-docker2<br></code></pre></td></tr></table></figure><h2 id="基本用法"><a href="#基本用法" class="headerlink" title="基本用法"></a>基本用法</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker ps <span class="hljs-comment"># 查看正在运行的容器</span><br>docker ps a <span class="hljs-comment"># 查看所有容器</span><br>docker start/stop <span class="hljs-built_in">id</span>/name <span class="hljs-comment"># 启动/停止某个容器</span><br>docker start -i <span class="hljs-built_in">id</span>/name <span class="hljs-comment"># 以交互方式启动一个容器</span><br>docker attach <span class="hljs-built_in">id</span>/name <span class="hljs-comment"># 进入某个容器 (使用 exit 退出后容器也跟着停止运行)</span><br>docker <span class="hljs-built_in">exec</span> -it <span class="hljs-built_in">id</span>/name <span class="hljs-comment"># 启动一个伪终端以交互式的方式进入某个运行的容器(使用 exit 退出后容器不停止运行)</span><br>docker <span class="hljs-built_in">exec</span> -it <容器> /bin/bash <span class="hljs-comment"># 进入容器</span><br>docker <span class="hljs-built_in">rm</span> <span class="hljs-built_in">id</span>/name <span class="hljs-comment"># 删除某个容器</span><br>docker network <span class="hljs-built_in">ls</span> <span class="hljs-comment"># 查询网络</span><br>docker network create <name> <span class="hljs-comment"># 创建网络</span><br></code></pre></td></tr></table></figure><h2 id="创建镜像"><a href="#创建镜像" class="headerlink" title="创建镜像"></a>创建镜像</h2><p><code>docker build -t xxx .</code></p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">FROM</span> node:latest<br><span class="hljs-keyword">WORKDIR</span><span class="language-bash"> /var/www/hexo</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> <span class="hljs-built_in">echo</span> <span class="hljs-string">"Asia/Shanghai"</span> > /etc/timezone</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> groupadd -r aaa && useradd -r -g aaa aaa</span><br><br><span class="hljs-keyword">RUN</span><span class="language-bash"> apt install git</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> npm install npm hexo-cli -g</span><br><br><span class="hljs-comment"># USER aaa</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> git config --global init.defaultBranch main \</span><br><span class="language-bash"> && git config --global user.name <span class="hljs-string">"aaa"</span> \</span><br><span class="language-bash"> && git config --global user.email <span class="hljs-string">"[email protected]"</span></span><br><br><span class="hljs-keyword">CMD</span><span class="language-bash"> npm install && hexo clean && hexo generate && hexo server</span><br><br><span class="hljs-comment"># EXPOSE 4000</span><br><span class="hljs-comment"># CMD ["/bin/bash"]</span><br></code></pre></td></tr></table></figure><h2 id="搭建-GitLab"><a href="#搭建-GitLab" class="headerlink" title="搭建 GitLab"></a>搭建 GitLab</h2><ul><li><p>下载镜像</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker search gitlab<br>docker pull gitlab/gitlab-ce<br></code></pre></td></tr></table></figure></li><li><p>启动容器</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker run \<br>--detach \<br>--hostname gitlab.example.com \ <span class="hljs-comment"># 设置主机名或域名</span><br>--publish 1443:443 \ <span class="hljs-comment"># 本地端口的映射,也可使用 443:443,可能有冲突</span><br>--publish 8080:80 \ <span class="hljs-comment"># 本地端口的映射,也可使用 80:80,可能有冲突</span><br>--publish 2222:22 \ <span class="hljs-comment"># 本地端口的映射,也可使用 22:22,可能有冲突</span><br>--name gitlab \ <span class="hljs-comment"># gitlab-ce 的镜像运行成为一个容器,这里是对容器的命名</span><br>--restart unless-stopped \ <span class="hljs-comment"># 设置重启方式</span><br>--volume /home/gitlab/etc:/etc/gitlab \ <span class="hljs-comment"># 将 gitlab 的配置文件目录映射到 /home/gitlab/etc 目录中</span><br>--volume /home/gitlab/log:/var/log/gitlab \ <span class="hljs-comment"># 将 gitlab 的日志文件目录映射到 /home/gitlab/log 目录中</span><br>--volume /home/gitlab/opt:/var/opt/gitlab \ <span class="hljs-comment"># 将 gitlab 的数据文件目录映射到 /home/gitlab/opt 目录中</span><br>gitlab/gitlab-ce <span class="hljs-comment"># 需要运行的镜像</span><br></code></pre></td></tr></table></figure></li><li><p>修改配置</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs bash">$ vim /home/gitlab/etc/gitlab.rb<br><br><span class="hljs-comment"># 配置 http 协议所使用的访问地址 --- 就是你主机的地址或者域名,不加端口号默认为 80</span><br><span class="hljs-comment"># 如果上述容器 80 端口映射的是非 80 端口,此处需要加上端口号:8080:80,那下面就得拼上 8080</span><br>external_url <span class="hljs-string">'http://192.168.31.110'</span><br><span class="hljs-comment"># external_url 'http://192.168.31.110:8080'</span><br><br><span class="hljs-comment"># 配置 ssh 协议所使用的访问地址和端口,此处不用加端口</span><br>gitlab_rails[<span class="hljs-string">'gitlab_ssh_host'</span>] = <span class="hljs-string">'192.168.31.110'</span><br><br><span class="hljs-comment"># 此端口是 run 时 22 端口映射的 22 端口,同理,如果映射的是非 22 端口,此处也得写映射后的端口</span><br>gitlab_rails[<span class="hljs-string">'gitlab_shell_ssh_port'</span>] = 22<br><span class="hljs-comment"># gitlab_rails['gitlab_shell_ssh_port'] = 2222</span><br><br>$ docker <span class="hljs-built_in">exec</span> gitlab gitlab-ctl reconfigure <span class="hljs-comment"># 使配置文件生效</span><br>$ docker restart gitlab <span class="hljs-comment"># 重启 gitlab</span><br></code></pre></td></tr></table></figure></li><li><p>获取 gitlab 的 root 密码</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker <span class="hljs-built_in">exec</span> -it gitlab /bin/bash <span class="hljs-comment"># 进入容器</span><br><span class="hljs-comment"># 容器内部执行</span><br><span class="hljs-built_in">cat</span> /etc/gitlab/initial_root_password <span class="hljs-comment"># initial_root_password 文件夹只有在首次启动 gitlab 才会出现,且 24 小时候会自动删除</span><br></code></pre></td></tr></table></figure></li><li><p>修改 gitlab 的 root 密码</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker <span class="hljs-built_in">exec</span> -it gitlab /bin/bash <span class="hljs-comment"># 进入容器</span><br><span class="hljs-comment"># 容器内部执行</span><br>gitlab-rails console -e production<br>user=User.<span class="hljs-built_in">where</span>(<span class="hljs-built_in">id</span>:1).first<br>user.password=<span class="hljs-string">"12345678"</span><br>user.password_confirmation=<span class="hljs-string">"12345678"</span><br>user.save!<br>quit<br></code></pre></td></tr></table></figure><p><img src="/tools/docker/images/gitlab.png" alt="gitlab 修改 root 密码"></p></li></ul><h2 id="搭建-WordPress"><a href="#搭建-WordPress" class="headerlink" title="搭建 WordPress"></a>搭建 WordPress</h2><ul><li><p>下载镜像</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker pull mysql<br>docker pull wordpress<br></code></pre></td></tr></table></figure></li><li><p>启动容器</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker run \<br>--detach \<br>--name wpdb \<br>--publish 3306:3306 \<br>--restart unless-stopped \<br>--volume /home/wordpressdb/lib:/var/lib/mysql \ <span class="hljs-comment"># 挂载数据到宿主机</span><br>--<span class="hljs-built_in">env</span> MYSQL_ROOT_PASSWORD=123456 \ <span class="hljs-comment"># 设置 MySQL 的 root 账户密码</span><br>--<span class="hljs-built_in">env</span> MYSQL_DATABASE=wordpress \ <span class="hljs-comment"># 创建数据库 wordpress</span><br>--<span class="hljs-built_in">env</span> MYSQL_USER=wordpress \ <span class="hljs-comment"># 创建用户 wordpress</span><br>--<span class="hljs-built_in">env</span> MYSQL_PASSWORD=wordpress \ <span class="hljs-comment"># 设置用户 wordpress 的密码</span><br>mysql<br><br>docker run \<br>--detach \<br>--name wp \<br>--publish 8080:80 \<br>--restart unless-stopped \<br>--<span class="hljs-built_in">link</span> wpdb:mysql \ <span class="hljs-comment"># 容器名 : 别名</span><br>--volume /home/wordpress:/var/www/html \<br>--<span class="hljs-built_in">env</span> WORDPRESS_DB_HOST=wpdb:3306 \<br>--<span class="hljs-built_in">env</span> WORDPRESS_DB_USER=wordpress \<br>--<span class="hljs-built_in">env</span> WORDPRESS_DB_PASSWORD=wordpress \<br>--<span class="hljs-built_in">env</span> WORDPRESS_DB_NAME=wordpress \<br>wordpress<br></code></pre></td></tr></table></figure></li><li><p>验证容器间通信</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker <span class="hljs-built_in">exec</span> -it wp bash <span class="hljs-comment"># 进入 wordpress 容器</span><br><span class="hljs-comment"># 容器内部执行</span><br>apt update && apt install iputils-ping <span class="hljs-comment"># 安装 ping</span><br>ping mysql<br><span class="hljs-comment"># or</span><br>ping wp-mysql<br></code></pre></td></tr></table></figure></li><li><p>创建数据库</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker <span class="hljs-built_in">exec</span> -it wp-mysql bash <span class="hljs-comment"># 进入容器</span><br><span class="hljs-comment"># 容器内部执行</span><br>mysql -u root -p <span class="hljs-comment"># 登录 MySQL</span><br>create database wordpress; <span class="hljs-comment"># 创建名为 wordpress 的数据库</span><br>quit<br></code></pre></td></tr></table></figure><p><img src="/tools/docker/images/create_database.png" alt="create database"></p></li><li><p>配置数据库<br><img src="/tools/docker/images/config_database.png" alt="config_database"></p></li><li><p>问题:ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ (2) —- 等会就好了</p></li></ul><h2 id="搭建-GitBook"><a href="#搭建-GitBook" class="headerlink" title="搭建 GitBook"></a>搭建 GitBook</h2><h2 id="搭建-Jeklly"><a href="#搭建-Jeklly" class="headerlink" title="搭建 Jeklly"></a>搭建 Jeklly</h2><p><a href="https://www.jekyll.com.cn/">https://www.jekyll.com.cn/</a></p><h2 id="docker-compose"><a href="#docker-compose" class="headerlink" title="docker-compose"></a>docker-compose</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker-compose -f docker-compose.yml up -d<br>docker-compose down<br>docker volume <span class="hljs-built_in">ls</span><br>docker volume prune<br></code></pre></td></tr></table></figure><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><code class="hljs yml"><span class="hljs-attr">version:</span> <span class="hljs-string">"3"</span><br><span class="hljs-attr">services:</span><br> <span class="hljs-attr">wordpressdb:</span><br> <span class="hljs-attr">image:</span> <span class="hljs-string">mysql:latest</span><br> <span class="hljs-attr">container_name:</span> <span class="hljs-string">wpdb</span><br> <span class="hljs-attr">volumes:</span><br> <span class="hljs-bullet">-</span> <span class="hljs-string">/home/wordpressdb/lib:/var/lib/mysql</span><br> <span class="hljs-attr">restart:</span> <span class="hljs-string">unless-stopped</span><br> <span class="hljs-attr">environment:</span><br> <span class="hljs-attr">MYSQL_ROOT_PASSWORD:</span> <span class="hljs-string">wpdbadmin</span><br> <span class="hljs-attr">MYSQL_DATABASE:</span> <span class="hljs-string">wordpress</span><br> <span class="hljs-attr">MYSQL_USER:</span> <span class="hljs-string">wordpress</span><br> <span class="hljs-attr">MYSQL_PASSWORD:</span> <span class="hljs-string">wordpress</span><br><br> <span class="hljs-attr">wordpress:</span><br> <span class="hljs-attr">image:</span> <span class="hljs-string">wordpress:latest</span><br> <span class="hljs-attr">container_name:</span> <span class="hljs-string">wp</span><br> <span class="hljs-attr">depends_on:</span><br> <span class="hljs-bullet">-</span> <span class="hljs-string">wordpressdb</span><br> <span class="hljs-attr">ports:</span><br> <span class="hljs-bullet">-</span> <span class="hljs-string">"80:80"</span><br> <span class="hljs-attr">volumes:</span><br> <span class="hljs-bullet">-</span> <span class="hljs-string">/home/wordpress:/var/www/html</span><br> <span class="hljs-attr">restart:</span> <span class="hljs-string">unless-stopped</span><br> <span class="hljs-attr">environment:</span><br> <span class="hljs-attr">WORDPRESS_DB_HOST:</span> <span class="hljs-string">wordpressdb:3306</span><br> <span class="hljs-attr">WORDPRESS_DB_USER:</span> <span class="hljs-string">wordpress</span><br> <span class="hljs-attr">WORDPRESS_DB_PASSWORD:</span> <span class="hljs-string">wordpress</span><br> <span class="hljs-attr">WORDPRESS_DB_NAME:</span> <span class="hljs-string">wordpress</span><br><span class="hljs-attr">volumes:</span><br> <span class="hljs-attr">wpdb_data:</span> {}<br> <span class="hljs-attr">wp_data:</span> {}<br></code></pre></td></tr></table></figure><h2 id="方法技巧"><a href="#方法技巧" class="headerlink" title="方法技巧"></a>方法技巧</h2><ul><li>设置容器时间和时区的方法。方法一:在dockerfile中增加<code>RUN echo "Asia/Shanghai" > /etc/timezone && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime</code>;方法二:在启动容器的时候,将宿主机的对应目录挂在到容器里<code>--volume /etc/localtime:/etc/localtime --volume /etc/timezone:/etc/timezone</code></li></ul><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li><a href="https://www.ruanyifeng.com/blog/2018/02/docker-wordpress-tutorial.html">Docker 微服务教程</a></li><li><a href="https://blog.csdn.net/qq_42997214/article/details/120988339">Docker images 存储路径修改</a></li><li><a href="https://zhuanlan.zhihu.com/p/337730352">群晖使用 Docker 安装并配置 GitLab 服务器</a></li><li><a href="https://zhuanlan.zhihu.com/p/462163501">如何优雅的构建 Docker Gitlab 环境</a></li><li><a href="https://zhuanlan.zhihu.com/p/253205843">Docker 搭建 gitlab 仓库</a></li><li><a href="https://zhuanlan.zhihu.com/p/63786567">使用 Docker 搭建 GitLab</a></li><li><a href="https://zhuanlan.zhihu.com/p/396245642">基于 Docker 的 gitlab 部署搭建</a></li><li><a href="https://blog.csdn.net/valada/article/details/81639706">Docker 入门之个人博客搭建教程</a></li><li><a href="https://blog.csdn.net/f59130/article/details/74014260">Docker 快速搭建个人博客网站 (wordpress+mysql)</a></li><li><a href="https://www.cnblogs.com/sunsky303/p/9396976.html">Docker 快速搭建 WordPress 博客网站</a></li><li><a href="https://www.cnblogs.com/soymilk2019/p/11577987.html">利用 docker 搭建 WordPress</a></li><li><a href="https://yeasy.gitbook.io/docker_practice">Docker - 从入门到实践</a></li><li><a href="https://hexo.io/zh-cn/">Hexo 文档</a></li><li><a href="https://wanf3ng.github.io/2021/01/29/%E4%BD%BF%E7%94%A8docker%E6%90%AD%E5%BB%BAHexo/#%E4%BD%BF%E7%94%A8dockerfile%E6%9E%84%E5%BB%BA%E9%95%9C%E5%83%8F">使用 docker 搭建 Hexo</a></li></ul>]]></content>
<categories>
<category>tools</category>
</categories>
<tags>
<tag>Docker</tag>
</tags>
</entry>
<entry>
<title>CMake</title>
<link href="/tools/cmake/"/>
<url>/tools/cmake/</url>
<content type="html"><![CDATA[<!--- [概述](#概述)- [入门](#入门)- [进阶](#进阶)- [变量](#变量)- [配置](#配置)- [CPack](#cpack)- [参考文献](#参考文献)--><h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><p>CMake 是一个跨平台的开源构建工具,使用 CMake 能够方便地管理依赖多个库的目录层次结构并生成 makefile 和使用 GNU make 来编译和连接程序。</p><h2 id="入门"><a href="#入门" class="headerlink" title="入门"></a>入门</h2><p>CMakeLists.txt 内容如下:</p><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs cmake"><span class="hljs-keyword">cmake_minimum_required</span>(VERSION <span class="hljs-number">3.18</span>) <span class="hljs-comment"># 设置 cmake 的最低版本</span><br><span class="hljs-keyword">project</span>(learn-cmake) <span class="hljs-comment"># 设置项目名字</span><br><span class="hljs-keyword">add_executable</span>(main main.cpp) <span class="hljs-comment"># 设定编译生成的二进制文件名字</span><br></code></pre></td></tr></table></figure><p>上面这三个命令是必须的,有这三行就可以编译最简单的一个 main.cpp 了。</p><h2 id="进阶"><a href="#进阶" class="headerlink" title="进阶"></a>进阶</h2><p>对于复杂项目,可在项目根目录放一个<code>CMakeLists.txt</code>文件,用于指定全局配置,在子项目里写各自的<code>CMakeLists.txt</code>。</p><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><code class="hljs cmake"><span class="hljs-comment"># 顶级 CMakeLists.txt</span><br><span class="hljs-keyword">cmake_minimum_required</span>(VERSION <span class="hljs-number">3.25</span>) <span class="hljs-comment"># 指定 cmake 最低版本</span><br><span class="hljs-keyword">project</span>(learn-cmake VERSION <span class="hljs-number">0.1</span> LANGUAGES C CXX) <span class="hljs-comment"># 指定项目名、版本和编程语言(C 和 C++ 混合编译)</span><br><br><span class="hljs-keyword">set</span>(CMAKE_INCLUDE_CURRENT_DIR <span class="hljs-keyword">ON</span>) <span class="hljs-comment"># 将当前路径添加为头文件包含路径,非必要</span><br><br><span class="hljs-keyword">set</span>(CMAKE_C_STANDARD <span class="hljs-number">11</span>) <span class="hljs-comment"># 指定 C 版本</span><br><span class="hljs-keyword">set</span>(CMAKE_C_STANDARD_REQUIRED <span class="hljs-keyword">True</span>)<br><span class="hljs-keyword">set</span>(CMAKE_CXX_STANDARD <span class="hljs-number">17</span>) <span class="hljs-comment"># 指定 C++ 版本</span><br><span class="hljs-keyword">set</span>(CMAKE_CXX_STANDARD_REQUIRED <span class="hljs-keyword">True</span>)<br><br><span class="hljs-keyword">message</span>(STATUS <span class="hljs-variable">${CMAKE_SYSTEM_NAME}</span>-<span class="hljs-variable">${CMAKE_SYSTEM_PROCESSOR}</span>-<span class="hljs-variable">${CMAKE_SYSTEM_VERSION}</span>)<br><br><span class="hljs-comment"># 添加头文件包含路径</span><br><span class="hljs-keyword">include_directories</span>(<span class="hljs-variable">${CMAKE_SOURCE_DIR}</span>/<span class="hljs-number">3</span>rd/<span class="hljs-keyword">include</span>)<br><span class="hljs-comment"># 添加库链接路径</span><br><span class="hljs-keyword">link_directories</span>(<br> <span class="hljs-variable">${CMAKE_SOURCE_DIR}</span>/<span class="hljs-number">3</span>rd/lib/<span class="hljs-variable">${CMAKE_SYSTEM_NAME}</span><br> <span class="hljs-variable">${CMAKE_SOURCE_DIR}</span>/<span class="hljs-number">3</span>rd/lib/<span class="hljs-variable">${CMAKE_SYSTEM_NAME}</span>/<span class="hljs-variable">${CMAKE_BUILD_TYPE}</span><br> <span class="hljs-variable">${CMAKE_SOURCE_DIR}</span>/<span class="hljs-number">3</span>rd/lib/<span class="hljs-variable">${CMAKE_SYSTEM_NAME}</span>-<span class="hljs-variable">${CMAKE_SYSTEM_PROCESSOR}</span><br> <span class="hljs-variable">${CMAKE_SOURCE_DIR}</span>/<span class="hljs-number">3</span>rd/lib/<span class="hljs-variable">${CMAKE_SYSTEM_NAME}</span>-<span class="hljs-variable">${CMAKE_SYSTEM_PROCESSOR}</span>/<span class="hljs-variable">${CMAKE_BUILD_TYPE}</span><br>)<br><span class="hljs-comment"># 链接库</span><br><span class="hljs-keyword">if</span> (LINUX)<br> <span class="hljs-keyword">link_libraries</span>(pthread)<br><span class="hljs-keyword">elseif</span>(APPLE)<br><span class="hljs-keyword">elseif</span>(WIN32)<br><span class="hljs-keyword">endif</span>()<br><br><span class="hljs-keyword">add_subdirectory</span>(tools) <span class="hljs-comment"># 子项目</span><br><br><span class="hljs-keyword">file</span>(CREATE_LINK <span class="hljs-variable">${CMAKE_SOURCE_DIR}</span>/data <span class="hljs-variable">${CMAKE_BINARY_DIR}</span>/data SYMBOLIC)<br></code></pre></td></tr></table></figure><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><code class="hljs cmake"><span class="hljs-comment"># 子项目 CMakeLists.txt</span><br><span class="hljs-keyword">cmake_minimum_required</span>(VERSION <span class="hljs-number">3.25</span>) <span class="hljs-comment"># 指定 cmake 最低版本</span><br><span class="hljs-keyword">project</span>(tools VERSION <span class="hljs-number">0.1</span> LANGUAGES C CXX) <span class="hljs-comment"># 指定项目名、版本和编程语言(C 和 C++ 混合编译)</span><br><br><span class="hljs-keyword">set</span>(CMAKE_INCLUDE_CURRENT_DIR <span class="hljs-keyword">ON</span>) <span class="hljs-comment"># 将当前路径添加为头文件包含路径,非必要</span><br><br><span class="hljs-keyword">set</span>(CMAKE_C_STANDARD <span class="hljs-number">11</span>) <span class="hljs-comment"># 指定 C 版本</span><br><span class="hljs-keyword">set</span>(CMAKE_C_STANDARD_REQUIRED <span class="hljs-keyword">True</span>)<br><span class="hljs-keyword">set</span>(CMAKE_CXX_STANDARD <span class="hljs-number">17</span>) <span class="hljs-comment"># 指定 C++ 版本</span><br><span class="hljs-keyword">set</span>(CMAKE_CXX_STANDARD_REQUIRED <span class="hljs-keyword">True</span>)<br><br><span class="hljs-comment"># 指定 find_package 查找路径</span><br><span class="hljs-keyword">if</span> (LINUX)<br> <span class="hljs-keyword">set</span>(CMAKE_PREFIX_PATH <span class="hljs-variable">${CMAKE_PREFIX_PATH}</span> <span class="hljs-string">"/opt/Qt/6.4.1/gcc_64"</span>)<br><span class="hljs-keyword">elseif</span>(APPLE)<br> <span class="hljs-keyword">set</span>(CMAKE_PREFIX_PATH <span class="hljs-variable">${CMAKE_PREFIX_PATH}</span> <span class="hljs-string">"/Applications/Qt/6.4.2/macos"</span>)<br> <span class="hljs-keyword">set</span>(CMAKE_OSX_ARCHITECTURES x86_64 arm64)<br><span class="hljs-keyword">elseif</span>(WIN32)<br> <span class="hljs-keyword">set</span>(CMAKE_PREFIX_PATH <span class="hljs-variable">${CMAKE_PREFIX_PATH}</span> <span class="hljs-string">"C:/Qt/6.4.2/msvc2019_64"</span>)<br><span class="hljs-keyword">endif</span>()<br><span class="hljs-keyword">find_package</span>(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets WebEngineWidgets)<br><span class="hljs-keyword">find_package</span>(Qt<span class="hljs-variable">${QT_VERSION_MAJOR}</span> REQUIRED COMPONENTS Widgets WebEngineWidgets)<br><br><span class="hljs-comment"># 添加头文件包含路径</span><br><span class="hljs-keyword">include_directories</span>(<br> <span class="hljs-variable">${CMAKE_CURRENT_SOURCE_DIR}</span>/src<br> <span class="hljs-variable">${CMAKE_CURRENT_SOURCE_DIR}</span>/src/utils<br>)<br><span class="hljs-comment"># 添加库链接路径</span><br><span class="hljs-keyword">link_directories</span>()<br><span class="hljs-comment"># 链接库</span><br><span class="hljs-keyword">link_libraries</span>()<br><br><span class="hljs-comment"># 收集源码文件</span><br><span class="hljs-keyword">aux_source_directory</span>(<span class="hljs-variable">${CMAKE_CURRENT_SOURCE_DIR}</span>src SOURCES)<br><span class="hljs-keyword">aux_source_directory</span>(<span class="hljs-variable">${CMAKE_CURRENT_SOURCE_DIR}</span>/src/utils SOURCES)<br><br><span class="hljs-comment"># 编译二进制</span><br><span class="hljs-keyword">add_executable</span>(<span class="hljs-variable">${PROJECT_NAME}</span> <span class="hljs-variable">${SOURCES}</span>)<br><span class="hljs-keyword">add_library</span>(<span class="hljs-variable">${PROJECT_NAME}</span>-shared SHARED <span class="hljs-variable">${SOURCES}</span>) <span class="hljs-comment"># 动态库</span><br><span class="hljs-keyword">add_library</span>(<span class="hljs-variable">${PROJECT_NAME}</span>-static STATIC <span class="hljs-variable">${SOURCES}</span>) <span class="hljs-comment"># 静态库</span><br><br><span class="hljs-comment"># 重命名库文件</span><br><span class="hljs-keyword">set_target_properties</span>(<span class="hljs-variable">${PROJECT_NAME}</span>-shared PROPERTIES OUTPUT_NAME qtopenglwidget)<br><span class="hljs-comment"># set_target_properties(${PROJECT_NAME} PROPERTIES CLEAN_DIRECT_OUTPUT 1) # 清理原库文件</span><br><span class="hljs-keyword">set_target_properties</span>(<span class="hljs-variable">${PROJECT_NAME}</span>-static PROPERTIES OUTPUT_NAME qtopenglwidget)<br><br><span class="hljs-keyword">add_subdirectory</span>(<span class="hljs-keyword">test</span>) <span class="hljs-comment"># 项目测试用例</span><br><br><span class="hljs-comment"># 收集头文件</span><br><span class="hljs-keyword">file</span>(GLOB HEADERS <span class="hljs-variable">${CMAKE_CURRENT_SOURCE_DIR}</span>/src/*.h)<br><span class="hljs-keyword">file</span>(COPY <span class="hljs-variable">${HEADERS}</span> DESTINATION <span class="hljs-variable">${CMAKE_CURRENT_BINARY_DIR}</span>/<span class="hljs-keyword">include</span>)<br><span class="hljs-keyword">file</span>(COPY <span class="hljs-variable">${CMAKE_CURRENT_SOURCE_DIR}</span>/data DESTINATION <span class="hljs-variable">${CMAKE_CURRENT_BINARY_DIR}</span>)<br></code></pre></td></tr></table></figure><figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><code class="hljs cmake"><span class="hljs-comment"># 子项目 CMakeLists.txt</span><br><span class="hljs-keyword">cmake_minimum_required</span>(VERSION <span class="hljs-number">3.25</span>)<br><span class="hljs-keyword">project</span>(<span class="hljs-variable">${PROJECT_NAME}</span>-<span class="hljs-keyword">test</span> VERSION <span class="hljs-number">0.1</span> LANGUAGES C CXX)<br><br><span class="hljs-keyword">set</span>(CMAKE_INCLUDE_CURRENT_DIR <span class="hljs-keyword">ON</span>)<br><br><span class="hljs-keyword">set</span>(CMAKE_C_STANDARD <span class="hljs-number">11</span>)<br><span class="hljs-keyword">set</span>(CMAKE_C_STANDARD_REQUIRED <span class="hljs-keyword">True</span>)<br><span class="hljs-keyword">set</span>(CMAKE_CXX_STANDARD <span class="hljs-number">17</span>)<br><span class="hljs-keyword">set</span>(CMAKE_CXX_STANDARD_REQUIRED <span class="hljs-keyword">True</span>)<br><br><span class="hljs-comment"># 指定 rpath</span><br><span class="hljs-keyword">set</span>(CMAKE_BUILD_WITH_INSTALL_RPATH <span class="hljs-keyword">TRUE</span>)<br><span class="hljs-keyword">if</span>(<span class="hljs-variable">${CMAKE_BUILD_TYPE}</span> <span class="hljs-keyword">MATCHES</span> <span class="hljs-string">"Debug"</span>)<br> <span class="hljs-keyword">set</span>(CMAKE_INSTALL_RPATH ..)<br><span class="hljs-keyword">elseif</span>(<span class="hljs-variable">${CMAKE_BUILD_TYPE}</span> <span class="hljs-keyword">MATCHES</span> <span class="hljs-string">"Release"</span>)<br> <span class="hljs-keyword">set</span>(CMAKE_INSTALL_RPATH .)<br><span class="hljs-keyword">endif</span>()<br><br><span class="hljs-comment"># 收集源码文件</span><br><span class="hljs-keyword">aux_source_directory</span>(<span class="hljs-variable">${CMAKE_CURRENT_SOURCE_DIR}</span> TEST_SRCS)<br><br><span class="hljs-comment"># 编译二进制</span><br><span class="hljs-keyword">add_executable</span>(<span class="hljs-variable">${PROJECT_NAME}</span> <span class="hljs-variable">${TEST_SRCS}</span>)<br><span class="hljs-keyword">target_include_directories</span>(<span class="hljs-variable">${PROJECT_NAME}</span> PRIVATE<br> <span class="hljs-variable">${CMAKE_CURRENT_BINARY_DIR}</span>/../<span class="hljs-keyword">include</span><br>)<br><span class="hljs-keyword">target_link_directories</span>(<span class="hljs-variable">${PROJECT_NAME}</span> PRIVATE<br> <span class="hljs-variable">${CMAKE_CURRENT_BINARY_DIR}</span>/../<br>)<br><span class="hljs-keyword">target_link_libraries</span>(<span class="hljs-variable">${PROJECT_NAME}</span><br> gtest gmock libtools.so<br>)<br></code></pre></td></tr></table></figure><h2 id="变量"><a href="#变量" class="headerlink" title="变量"></a>变量</h2><ul><li><code>CMAKE_SOURCE_DIR</code> 是 CMake 内置的变量之一,它表示项目根目录的路径。<br>当使用 CMake 构建项目时,通常会将 CMakeLists.txt 文件放在项目根目录中,此时可以使用 <code>CMAKE_SOURCE_DIR</code> 变量来引用项目根目录中的文件或目录。例如,<code>${CMAKE_SOURCE_DIR}/include</code> 表示项目根目录中的 <code>include</code> 目录的路径。<br>需要注意的是,<code>CMAKE_SOURCE_DIR</code> 表示的是项目根目录的路径,而不是当前处理的 CMakeLists.txt 文件所在的目录的路径。如果需要引用当前处理的 CMakeLists.txt 文件所在目录的路径,应该使用 <code>CMAKE_CURRENT_LIST_DIR</code> 变量。</li><li><code>CMAKE_CURRENT_SOURCE_DIR</code> 是 CMake 内置的变量之一,它表示当前处理的 CMakeLists.txt 文件所在目录的路径。<br>当使用 CMake 构建项目时,可以使用 <code>CMAKE_CURRENT_SOURCE_DIR</code> 来引用当前处理的 CMakeLists.txt 文件所在目录中的文件或目录。例如,<code>${CMAKE_CURRENT_SOURCE_DIR}/src</code> 表示当前处理的 CMakeLists.txt 文件所在目录中的 <code>src</code> 目录的路径。<br>需要注意的是,<code>CMAKE_CURRENT_SOURCE_DIR</code> 表示的是当前处理的 CMakeLists.txt 文件所在目录的路径,而不是项目根目录的路径。如果需要引用项目根目录的路径,应该使用 <code>CMAKE_SOURCE_DIR</code> 变量。</li><li><code>CMAKE_CURRENT_LIST_DIR</code>是一个 CMake 内置的变量,它表示当前处理的 CMakeLists.txt 文件所在的目录的路径。该变量的值在 CMake 运行时动态计算,因此它会随着处理的 CMakeLists.txt 文件的不同而发生变化。<br>通过使用 <code>CMAKE_CURRENT_LIST_DIR</code> 变量,可以方便地引用当前处理的 CMakeLists.txt 文件所在目录中的文件或目录。例如,可以使用 <code>${CMAKE_CURRENT_LIST_DIR}/include</code> 来引用当前处理的 CMakeLists.txt 文件所在目录中的 include 目录。</li><li><code>PROJECT_ROOT</code> 和 <code>CMAKE_SOURCE_DIR</code> 的区别<br><code>PROJECT_ROOT</code> 不是 CMake 内置的变量,它通常是由项目的开发者在 CMakeLists.txt 文件中定义的。与此不同,<code>CMAKE_SOURCE_DIR</code> 是 CMake 内置的变量,它指向项目源代码根目录的路径。<br>因此,<code>PROJECT_ROOT</code> 和 <code>CMAKE_SOURCE_DIR</code> 的区别在于其定义的位置和目的。<code>PROJECT_ROOT</code> 是由项目开发者定义的变量,可以用于自定义项目的根目录路径,而 <code>CMAKE_SOURCE_DIR</code> 是 CMake 内置的变量,指向项目源代码根目录的路径。</li><li><code>CMAKE_CURRENT_LIST_DIR</code> 和 <code>CMAKE_CURRENT_SOURCE_DIR</code> 的区别<br><code>CMAKE_CURRENT_LIST_DIR</code> 和 <code>CMAKE_CURRENT_SOURCE_DIR</code> 都是 CMake 内置的变量,它们的作用是表示当前处理的 CMakeLists.txt 文件所在的目录的路径。<br>区别在于,<code>CMAKE_CURRENT_LIST_DIR</code> 表示的是当前处理的 CMakeLists.txt 文件所在的目录的路径,而 <code>CMAKE_CURRENT_SOURCE_DIR</code> 表示的是当前处理的源文件所在的目录的路径。<br>如果 CMakeLists.txt 文件包含在一个子目录中,则 <code>CMAKE_CURRENT_LIST_DIR</code> 和 <code>CMAKE_CURRENT_SOURCE_DIR</code> 的值可能不同,因为它们表示的是不同的目录。例如,如果 CMakeLists.txt 文件位于项目根目录的 <code>src</code> 子目录中,而源文件位于 <code>src</code> 子目录的 <code>lib</code> 子目录中,则 <code>CMAKE_CURRENT_LIST_DIR</code> 的值为 <code>${PROJECT_SOURCE_DIR}/src</code>,而 <code>CMAKE_CURRENT_SOURCE_DIR</code> 的值为 <code>${PROJECT_SOURCE_DIR}/src/lib</code>。<br>因此,需要根据具体情况选择使用 <code>CMAKE_CURRENT_LIST_DIR</code> 还是 <code>CMAKE_CURRENT_SOURCE_DIR</code>。如果需要引用当前处理的 CMakeLists.txt 文件所在目录中的文件或目录,应该使用 <code>CMAKE_CURRENT_LIST_DIR</code>;如果需要引用当前源文件所在目录中的文件或目录,应该使用 <code>CMAKE_CURRENT_SOURCE_DIR</code>。</li></ul><h2 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h2><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs json"><span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"cmake.configureEnvironment"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"CMAKE_PREFIX_PATH"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"C:/Qt/6.6.2/msvc2019_64"</span><br> <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span><br> <span class="hljs-attr">"cmake.debugConfig"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"args"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span><span class="hljs-punctuation">]</span><br> <span class="hljs-punctuation">}</span><br><span class="hljs-punctuation">}</span><br></code></pre></td></tr></table></figure><h2 id="CPack"><a href="#CPack" class="headerlink" title="CPack"></a>CPack</h2><h2 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h2><ul><li><a href="https://www.leadroyal.cn/?p=781">CMake 多模块的构建方式</a></li><li><a href="https://zhuanlan.zhihu.com/p/149828002">CMake 入门</a></li><li><a href="https://blog.xizhibei.me/2020/04/20/cmake-5-install-package-and-export/">CMake 系列(五)安装、打包与导出</a></li><li><a href="https://blog.csdn.net/qq_26849933/article/details/127139052">CMake 常用命令(六)link_libraries 和 target_link_libraries 链接库</a></li><li><a href="https://blog.csdn.net/yue597215286/article/details/129708886">CMake 如何控制两个文件生成的依赖关系</a></li><li><a href="https://blog.csdn.net/andylauren/article/details/99841848">(9)CMake 入门笔记–同时生成动态库与静态库</a></li><li><a href="https://www.coder.work/article/7047041">cmake - 如何在 CMake 中重命名库文件名?</a></li><li><a href="https://www.cnblogs.com/sonnet/p/15187916.html">Cmake 参数修改之 CFLAGS 和 CXXFLAGS</a></li><li><a href="https://blog.csdn.net/rangfei/article/details/125651845">cmake(13):构建时设置预处理宏定义以及 add_compile_definitions 命令详解</a></li><li><a href="https://blog.csdn.net/qq_29493353/article/details/90205415">CMake 快速制作 RPM 包</a></li></ul>]]></content>
<categories>
<category>tools</category>
</categories>
<tags>
<tag>Tool</tag>
</tags>
</entry>
<entry>
<title>Git</title>
<link href="/tools/git/"/>
<url>/tools/git/</url>
<content type="html"><![CDATA[<h2 id="1-简介"><a href="#1-简介" class="headerlink" title="1 简介"></a>1 简介</h2><h2 id="2-命令"><a href="#2-命令" class="headerlink" title="2 命令"></a>2 命令</h2><h3 id="2-1-git-clone"><a href="#2-1-git-clone" class="headerlink" title="2.1 git clone"></a>2.1 git clone</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">git <span class="hljs-built_in">clone</span> url <directory-name> <span class="hljs-comment"># 将拉下来的仓库文件夹重命名</span><br></code></pre></td></tr></table></figure><h3 id="2-2-git-add"><a href="#2-2-git-add" class="headerlink" title="2.2 git add"></a>2.2 git add</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">git add . <span class="hljs-comment"># 暂存所有修改</span><br>git add <file> <span class="hljs-comment"># 暂存某个文件</span><br>git add --patch <file> <span class="hljs-comment"># 生成 patch</span><br></code></pre></td></tr></table></figure><h3 id="2-3-git-commit"><a href="#2-3-git-commit" class="headerlink" title="2.3 git commit"></a>2.3 git commit</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs bash">git commit --amend <span class="hljs-comment"># 将暂存的修改与上一个提交合并</span><br>git commit --no-edit <span class="hljs-comment"># 不修改内容</span><br>git commit --no-edit --author=<span class="hljs-string">"name<email>"</span> <span class="hljs-comment"># 修改上一个提交的作者</span><br>git commit --amend --edit <span class="hljs-comment"># 修改 commit 信息</span><br>git commit --fixup=<Hash> <span class="hljs-comment"># 将修改作为补丁提交</span><br></code></pre></td></tr></table></figure><h3 id="2-4-git-pull"><a href="#2-4-git-pull" class="headerlink" title="2.4 git pull"></a>2.4 git pull</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">git pull origin --rebase <span class="hljs-comment"># 拉取远程分支并 rebase</span><br></code></pre></td></tr></table></figure><h3 id="2-5-git-push"><a href="#2-5-git-push" class="headerlink" title="2.5 git push"></a>2.5 git push</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs bash">git push -f origin<br>git push --delete origin <branch> <span class="hljs-comment"># 删除远程分支</span><br>git push <remotename> <commit SHA>:<remotebranchname><br>git push origin 123456:refs/heads/branch<br></code></pre></td></tr></table></figure><h3 id="2-6-git-fetch"><a href="#2-6-git-fetch" class="headerlink" title="2.6 git fetch"></a>2.6 git fetch</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">git fetch origin<br></code></pre></td></tr></table></figure><h3 id="2-7-git-rebase"><a href="#2-7-git-rebase" class="headerlink" title="2.7 git rebase"></a>2.7 git rebase</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">git rebase -i <Hash><br>git rebase --autosquash -i <Hash><br></code></pre></td></tr></table></figure><h3 id="2-8-git-remote"><a href="#2-8-git-remote" class="headerlink" title="2.8 git remote"></a>2.8 git remote</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs bash">git remote -v<br>git remote show origin<br>git remote prune origin<br>git remote set-url dev ssh://git@host:port/~/xxx.git<br></code></pre></td></tr></table></figure><h3 id="2-9-git-cherry-pick"><a href="#2-9-git-cherry-pick" class="headerlink" title="2.9 git cherry-pick"></a>2.9 git cherry-pick</h3><h3 id="2-10-git-diff"><a href="#2-10-git-diff" class="headerlink" title="2.10 git diff"></a>2.10 git diff</h3><p>commit_A: 前一次提交的 hash 值。<br>commit_B: 需要导出位置的提交的 hash 值。<br><code>git diff commit_A commit_B > patch.patch</code><br>注:导出的 patch 文件是两个提交信息之间所有的差异。</p><h3 id="2-11-git-log"><a href="#2-11-git-log" class="headerlink" title="2.11 git log"></a>2.11 git log</h3><h3 id="2-12-git-show"><a href="#2-12-git-show" class="headerlink" title="2.12 git show"></a>2.12 git show</h3><h3 id="2-13-git-branch"><a href="#2-13-git-branch" class="headerlink" title="2.13 git branch"></a>2.13 git branch</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">git branch -m <old name> <new name> <span class="hljs-comment"># 修改本地分支名</span><br></code></pre></td></tr></table></figure><h3 id="2-14-git-config"><a href="#2-14-git-config" class="headerlink" title="2.14 git config"></a>2.14 git config</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">git config --global init.defaultBranch <defaultBranch> <span class="hljs-comment"># 设置默认分支名</span><br></code></pre></td></tr></table></figure><h2 id="3-进阶操作"><a href="#3-进阶操作" class="headerlink" title="3 进阶操作"></a>3 进阶操作</h2><h3 id="3-1-Git-global-setup"><a href="#3-1-Git-global-setup" class="headerlink" title="3.1 Git global setup"></a>3.1 Git global setup</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">git config --global user.name <span class="hljs-string">"xxx"</span><br>git config --global user.email <span class="hljs-string">"[email protected]"</span><br></code></pre></td></tr></table></figure><h3 id="3-2-Create-a-new-repository"><a href="#3-2-Create-a-new-repository" class="headerlink" title="3.2 Create a new repository"></a>3.2 Create a new repository</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs bash">git <span class="hljs-built_in">clone</span> [email protected]:xxx/xyz.git<br><span class="hljs-built_in">cd</span> xyz<br><span class="hljs-built_in">touch</span> README.md<br>git add README.md<br>git commit -m <span class="hljs-string">"add README"</span><br>git push -u origin master<br></code></pre></td></tr></table></figure><h3 id="3-3-Push-an-existing-folder"><a href="#3-3-Push-an-existing-folder" class="headerlink" title="3.3 Push an existing folder"></a>3.3 Push an existing folder</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">cd</span> existing_folder<br>git init<br>git remote add origin [email protected]:xxx/xyz.git<br>git add .<br>git commit -m <span class="hljs-string">"Initial commit"</span><br>git push -u origin master<br></code></pre></td></tr></table></figure><h3 id="3-4-Push-an-existing-Git-repository"><a href="#3-4-Push-an-existing-Git-repository" class="headerlink" title="3.4 Push an existing Git repository"></a>3.4 Push an existing Git repository</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">cd</span> existing_repo<br>git remote rename origin old-origin<br>git remote add origin [email protected]:xxx/xyz.git<br>git push -u origin --all<br>git push -u origin --tags<br></code></pre></td></tr></table></figure><h3 id="3-5-忽略更改"><a href="#3-5-忽略更改" class="headerlink" title="3.5 忽略更改"></a>3.5 忽略更改</h3><ul><li><p><code>.gitignore</code></p><ul><li>说明:显式地阻止提交文件。</li><li>优势:.gitignore 文件本身提交至远程仓库,全组共享忽略文件配置。</li><li>局限:如果项目已经存在远程仓库,即使被加入 .gitignore,仍然可以进行修改并提交。本地的修改会显示在 git status 结果中。</li></ul></li><li><p><code>.git/info/exclude</code></p><ul><li>说明:显式地阻止提交文件。</li><li>优势:exclude 文件本身不会提交至远程仓库,因此适合放一些个人定制的「gitignore」项目。</li><li>局限:和 .gitignore 存在同样地局限。文件若已存在远程仓库,则本地修改仍可以提交至远程仓库。本地的修改会显示在 git status 结果中。</li></ul></li><li><p><code>assume-unchanged</code></p><ul><li>说明:声明本地远程都不会修改这个文件。</li><li>优势:git 直接跳过这些文件的处理以提升性能。文件不会出现在 git status。</li><li>局限:不适合本地或远程需要修改的文件。本地会忽略掉之后远程文件的修改。</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">git update-index --assume-unchanged<br></code></pre></td></tr></table></figure></li><li><p><code>skip-worktree</code></p><ul><li>说明:声明忽略文件的本地修改。</li><li>优势:本地可以对文件做一些个人定制。文件不会出现在 git status。</li><li>局限:拉取远程文件更新,或切换分支时有可能出现冲突,需要撤销忽略后手动解决冲突。</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">git update-index --assume-unchanged<br></code></pre></td></tr></table></figure></li></ul><h3 id="3-6-设置跟踪关系"><a href="#3-6-设置跟踪关系" class="headerlink" title="3.6 设置跟踪关系"></a>3.6 设置跟踪关系</h3><ul><li><p>新建一个分支并设置跟踪关系</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">git checkout -b new_branch_name [--track] origin/remote_branch_name <span class="hljs-comment"># --track 选项可以省略</span><br></code></pre></td></tr></table></figure></li><li><p>设置已有分支和远端分支的跟踪关系</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">git branch -u origin/remote_branch_name local_branch_name<br><span class="hljs-comment"># or</span><br>git branch --set-upstream-to=origin/branch_name local_branch_name<br></code></pre></td></tr></table></figure><blockquote><p>-u 选项是 –set-upstream-to 的简写;<br>local_branch_name 可以省略,默认值为当前分支。</p></blockquote></li></ul><h3 id="3-7-通过哈希值查找提交"><a href="#3-7-通过哈希值查找提交" class="headerlink" title="3.7 通过哈希值查找提交"></a>3.7 通过哈希值查找提交</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">git <span class="hljs-built_in">log</span> <Hash><br>git show <Hash><br></code></pre></td></tr></table></figure><h3 id="3-8-修改分支名"><a href="#3-8-修改分支名" class="headerlink" title="3.8 修改分支名"></a>3.8 修改分支名</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">git push --delete origin <branch> <span class="hljs-comment"># 删除远程分支</span><br>git branch -m <old name> <new name> <span class="hljs-comment"># 修改本地分支名</span><br>git push origin <new branch> <span class="hljs-comment"># 推送本地分支</span><br></code></pre></td></tr></table></figure><h3 id="3-9-创建-git-仓库"><a href="#3-9-创建-git-仓库" class="headerlink" title="3.9 创建 git 仓库"></a>3.9 创建 git 仓库</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">git init --bare aaa.git <span class="hljs-comment"># 创建远程仓库</span><br>git init aaa <span class="hljs-comment"># 创建本地仓库</span><br></code></pre></td></tr></table></figure><h4 id="3-9-1-配置环境"><a href="#3-9-1-配置环境" class="headerlink" title="3.9.1 配置环境"></a>3.9.1 配置环境</h4><ol><li>安装<code>apt install git</code></li><li>创建用户<code>adduser git</code></li><li>设置仓库默认分支名<code>git config --global init.defaultBranch main</code></li><li>创建证书登录<br>将需要登录用户的公钥,默认为<code>~/.ssh/id_rsa.pub</code>,导入到<code>/home/git/.ssh/authorized_keys</code>,一行一个。<br><code>cat .ssh/id_rsa.pub >> /home/.git/.ssh/authorized_keys</code></li><li>初始化 Git 仓库<br><code>--bare</code>会创建一个裸仓库,裸仓库没有工作区,因为服务器上的 Git 仓库纯粹是为了共享,所以不让用户直接登录到服务器上去改工作区,并且服务器上的 Git 仓库通常都以.git 结尾。<br><code>git init --bare project.git</code><br>然后,把 owner 改为 git:<br><code>chown -R git:git project.git</code></li><li>修改远程仓库默认分支名<br><code>cd project.git && git symbolic-ref HEAD refs/heads/main</code></li><li>禁用 shell 登录<br>出于安全考虑,不允许 git 用户登录 shell,修改<code>/etc/passwd</code>中<code>git:x:6666:6666:,,,:/home/git:/bin/bash</code>为<code>git:x:6666:6666:,,,:/home/git:/bin/git-shell</code></li><li>拉取仓库<br><code>git clone git@server:xxx/project.git</code></li></ol><ul><li><a href="https://blog.csdn.net/y_s_jun/article/details/117433339">修改 GIT 初始分支名称</a></li><li><a href="https://feeding.cloud.geek.nz/posts/setting-default-git-branch-in-bare/">Setting the default git branch in a bare repository</a></li></ul><h4 id="3-9-2-管理权限"><a href="#3-9-2-管理权限" class="headerlink" title="3.9.2 管理权限"></a>3.9.2 管理权限</h4><ul><li>要方便管理公钥,用 Gitosis</li><li>要像 SVN 那样变态地控制权限,用 Gitolite</li></ul><h4 id="3-9-3-配置空仓库"><a href="#3-9-3-配置空仓库" class="headerlink" title="3.9.3 配置空仓库"></a>3.9.3 配置空仓库</h4><ul><li><p>Git global setup</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">git config --global user.name <span class="hljs-string">"Laplace"</span><br>git config --global user.email <span class="hljs-string">"[email protected]"</span><br></code></pre></td></tr></table></figure></li><li><p>Create a new repository</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs bash">git <span class="hljs-built_in">clone</span> [email protected]:ut000893/test.git<br><span class="hljs-built_in">cd</span> <span class="hljs-built_in">test</span><br><span class="hljs-built_in">touch</span> README.md<br>git add README.md<br>git commit -m <span class="hljs-string">"add README"</span><br>git push -u origin master<br></code></pre></td></tr></table></figure></li><li><p>Push an existing folder</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">cd</span> existing_folder<br>git init<br>git remote add origin [email protected]:ut000893/test.git<br>git add .<br>git commit -m <span class="hljs-string">"Initial commit"</span><br>git push -u origin master<br></code></pre></td></tr></table></figure></li><li><p>Push an existing Git repository</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">cd</span> existing_repo<br>git remote rename origin old-origin<br>git remote add origin [email protected]:ut000893/test.git<br>git push -u origin --all<br>git push -u origin --tags<br></code></pre></td></tr></table></figure></li></ul><h3 id="3-10-子模块"><a href="#3-10-子模块" class="headerlink" title="3.10 子模块"></a>3.10 子模块</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs bash">git remote set-head origin -a <span class="hljs-comment"># 设置 HEAD</span><br><span class="hljs-comment"># add</span><br>git submodule add [email protected]:aaa/xxx.git <span class="hljs-comment"># 添加子模块</span><br>git submodule add -b <branch> --name <name> <repo-url> <<span class="hljs-built_in">local</span> <span class="hljs-built_in">dir</span>> <span class="hljs-comment"># 添加子模块</span><br>git config -f .gitmodules submodule.xxx.branch main <span class="hljs-comment"># 设置默认分支</span><br>git submodule set-url xxx [email protected]:aaa/xxx.git <span class="hljs-comment"># 设置子模块仓库地址</span><br>git submodule <span class="hljs-built_in">sync</span> --recursive <span class="hljs-comment"># 同步配置文件到本地</span><br>git submodule update --init --recursive <span class="hljs-comment"># 递归更新仓库</span><br>git submodule update --remote --rebase<br>git submodule update --remote --merge<br><span class="hljs-comment"># remove</span><br>git submodule deinit <submodule_path> <span class="hljs-comment"># 删除本地配置 .git/config</span><br><span class="hljs-built_in">rm</span> -rf .git/modules/<submodule_path><br>git <span class="hljs-built_in">rm</span> -f <submodule_path> <span class="hljs-comment"># 删除子模块配置 .gitmodules</span><br></code></pre></td></tr></table></figure><h2 id="4-git-lfs"><a href="#4-git-lfs" class="headerlink" title="4 git lfs"></a>4 git lfs</h2><ul><li>安装 git lfs</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo apt install git-lfs<br>git lfs install<br>git lfs track <span class="hljs-string">"*.psd"</span><br></code></pre></td></tr></table></figure><ul><li>移除 git lfs</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs bash">git lfs pull<br><span class="hljs-comment"># or</span><br>git lfs fetch<br><span class="hljs-built_in">rm</span> .gitattributes<br>git <span class="hljs-built_in">rm</span> --cached -r *<br>git add .<br></code></pre></td></tr></table></figure><ul><li><a href="https://git-lfs.github.com/">Git Large File Storage</a></li><li><a href="https://www.jianshu.com/p/493b81544f80">Git LFS 的使用</a></li></ul><h2 id="5-参考文献"><a href="#5-参考文献" class="headerlink" title="5 参考文献"></a>5 参考文献</h2><ul><li><a href="git%E6%80%9D%E7%BB%B4%E5%AF%BC%E5%9B%BE.pdf">git 思维导图</a></li><li><a href="https://mengqi92.github.io/2020/07/17/hide-files-from-git/">Git 小技巧 - 忽略不想要提交的本地修改</a></li><li><a href="https://blog.csdn.net/big_thinker/article/details/52664710">设置 git 分支的跟踪关系</a></li><li><a href="https://www.daimajiaoliu.com/daima/47d9f31571003e8">deepin 下搭建自己的 git 服务器</a></li><li><a href="https://www.liaoxuefeng.com/wiki/896043488029600/899998870925664">搭建 Git 服务器</a></li><li><a href="https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E5%AD%90%E6%A8%A1%E5%9D%97">7.11 Git 工具 - 子模块</a></li><li><a href="https://zhuanlan.zhihu.com/p/87053283">Git中submodule的使用</a></li><li><a href="https://zhuanlan.zhihu.com/p/374662328">Git Submodule 使用</a></li></ul>]]></content>
<categories>
<category>tools</category>
</categories>
<tags>
<tag>Tool</tag>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title>Google Test</title>
<link href="/tools/gtest/"/>
<url>/tools/gtest/</url>
<content type="html"><![CDATA[<h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><p>测试用例工作空间独立,在 CaseA 中给成员变量赋值无法在 CaseB 中访问,使用<code>TEST_F</code>尤其需要注意这个特点。</p><p><code>TEST</code>常用于测试互相独立的单个方法。<br><code>TEST_F</code>常用于测试几个测试用例依赖同一份数据的情况。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-comment">/* 使用 TEST 的例子 */</span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">"utils.h"</span></span><br><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><gtest/gtest.h></span></span><br><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> utils;<br><br><span class="hljs-built_in">TEST</span>(UtilsTest, SplitString1)<br>{<br> <span class="hljs-comment">// 独立的方法</span><br>}<br><br><span class="hljs-built_in">TEST</span>(UtilsTest, SplitString2)<br>{<br> <span class="hljs-comment">// 独立的方法</span><br>}<br></code></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-comment">/* 使用 TEST_F 的例子 */</span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">"foo.h"</span></span><br><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><gtest/gtest.h></span></span><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">FooTest</span> : <span class="hljs-keyword">public</span> testing::Test<br>{<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-built_in">FooTest</span>();<br> ~<span class="hljs-built_in">FooTest</span>() <span class="hljs-keyword">override</span>;<br><br> <span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">void</span> <span class="hljs-title">SetUpTestCase</span><span class="hljs-params">()</span></span>;<br> <span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">void</span> <span class="hljs-title">TearDownTestCase</span><span class="hljs-params">()</span></span>;<br><br><span class="hljs-keyword">protected</span>:<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">SetUp</span><span class="hljs-params">()</span> <span class="hljs-keyword">override</span></span>;<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">TearDown</span><span class="hljs-params">()</span> <span class="hljs-keyword">override</span></span>;<br><br><span class="hljs-keyword">protected</span>:<br> Foo *m_foo = <span class="hljs-literal">nullptr</span>;<br>};<br><br>FooTest::<span class="hljs-built_in">FooTest</span>()<br> : <span class="hljs-built_in">m_foo</span>(<span class="hljs-keyword">new</span> Foo)<br>{<br> <span class="hljs-comment">// 构造成员</span><br>}<br><br>FooTest::~<span class="hljs-built_in">FooTest</span>()<br>{<br> <span class="hljs-comment">// 析构成员</span><br> <span class="hljs-keyword">delete</span> m_foo;<br>}<br><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MifDataLoaderTest::SetUpTestCase</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-comment">// Called before first test case</span><br>}<br><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MifDataLoaderTest::TearDownTestCase</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-comment">// Called after last test case</span><br>}<br><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">FooTest::SetUp</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-comment">// Called before each test case</span><br>}<br><br><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">FooTest::TearDown</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-comment">// Called after each test case</span><br>}<br><br><span class="hljs-built_in">TEST_F</span>(FooTest, Api1)<br>{<br> <span class="hljs-comment">// test case</span><br>}<br><br><span class="hljs-built_in">TEST_F</span>(FooTest, Api2)<br>{<br> <span class="hljs-comment">// test case</span><br>}<br></code></pre></td></tr></table></figure><h2 id="断言"><a href="#断言" class="headerlink" title="断言"></a>断言</h2><p>gtest 中,断言的宏可以理解为分为两类,一类是 ASSERT 系列,一类是 EXPECT 系列。</p><ol><li><code>ASSERT_*</code>系列的断言,当检查点失败时,退出当前函数(注意:并非退出当前案例)。</li><li><code>EXPECT_*</code>系列的断言,当检查点失败时,继续往下执行。</li></ol><h3 id="布尔值检查"><a href="#布尔值检查" class="headerlink" title="布尔值检查"></a>布尔值检查</h3><table><thead><tr><th>Fatal assertion</th><th>Nonfatal assertion</th><th>Verifies</th></tr></thead><tbody><tr><td>ASSERT_TRUE(condition);</td><td>EXPECT_TRUE(condition);</td><td>condition is true</td></tr><tr><td>ASSERT_FALSE(condition);</td><td>EXPECT_FALSE(condition);</td><td>condition is false</td></tr></tbody></table><h3 id="数值型数据检查"><a href="#数值型数据检查" class="headerlink" title="数值型数据检查"></a>数值型数据检查</h3><table><thead><tr><th>Fatal assertion</th><th>Nonfatal assertion</th><th>Verifies</th></tr></thead><tbody><tr><td>ASSERT_EQ(expected, actual);</td><td>EXPECT_EQ(expected, actual);</td><td>expected == actual</td></tr><tr><td>ASSERT_NE(val1, val2);</td><td>EXPECT_NE(val1, val2);</td><td>val1 != val2</td></tr><tr><td>ASSERT_LT(val1, val2);</td><td>EXPECT_LT(val1, val2);</td><td>val1 < val2</td></tr><tr><td>ASSERT_LE(val1, val2);</td><td>EXPECT_LE(val1, val2);</td><td>val1 <= val2</td></tr><tr><td>ASSERT_GT(val1, val2);</td><td>EXPECT_GT(val1, val2);</td><td>val1 > val2</td></tr><tr><td>ASSERT_GE(val1, val2);</td><td>EXPECT_GE(val1, val2);</td><td>val1 >= val2</td></tr></tbody></table><h3 id="字符串检查"><a href="#字符串检查" class="headerlink" title="字符串检查"></a>字符串检查</h3><table><thead><tr><th>Fatal assertion</th><th>Nonfatal assertion</th><th>Verifies</th></tr></thead><tbody><tr><td>ASSERT_STREQ(expected_str, actual_str);</td><td>EXPECT_STREQ(expected_str, actual_str);</td><td>the two C strings have the same content</td></tr><tr><td>ASSERT_STRNE(str1, str2);</td><td>EXPECT_STRNE(str1, str2);</td><td>the two C strings have different content</td></tr><tr><td>ASSERT_STRCASEEQ(expected_str, actual_str);</td><td>EXPECT_STRCASEEQ(expected_str, actual_str);</td><td>the two C strings have the same content, ignoring case</td></tr><tr><td>ASSERT_STRCASENE(str1, str2);</td><td>EXPECT_STRCASENE(str1, str2);</td><td>the two C strings have different content, ignoring case</td></tr></tbody></table><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><ul><li><a href="https://github.com/google/googletest">googletest source</a></li><li><a href="https://github.com/google/googletest/blob/v1.8.x/googlemock/docs/Documentation.md">googletest-gmock 官方文档</a></li><li><a href="https://www.cnblogs.com/coderzh/archive/2009/04/06/1426755.html">玩转 Google 开源 C++ 单元测试框架 Google Test 系列 (gtest)</a></li><li><a href="https://zhuanlan.zhihu.com/p/101906555">googletest-gmock 使用示例</a></li><li><a href="https://blog.csdn.net/carolzhang8406/article/details/54668462">gtest Test_F 和 Test 区别</a></li></ul>]]></content>
<categories>
<category>tools</category>
</categories>
<tags>
<tag>GTest</tag>
</tags>
</entry>
<entry>
<title>Systemd</title>
<link href="/linux/systemd/"/>
<url>/linux/systemd/</url>
<content type="html"><![CDATA[<h2 id="1-简介"><a href="#1-简介" class="headerlink" title="1 简介"></a>1 简介</h2><p>systemd 是 Linux 系统的一组基本构建块。它提供了一个以 PID 1 运行的系统和服务管理器,并启动了系统的其余部分。systemd 提供积极的并行化功能,使用套接字和 D-Bus 激活来启动服务,按需启动守护程序,使用 Linux 控制组跟踪进程,维护安装和自动挂载点以及实现精心设计的基于事务依赖关系的服务控制逻辑。systemd 支持 SysV 和 LSB 初始化脚本,并替代 sysvinit。其他部分包括日志记录守护程序,用于控制基本系统配置的实用程序,例如主机名,日期,区域设置,维护已登录用户和正在运行的容器和虚拟机的列表,系统帐户,运行时目录和设置,以及用于管理简单网络的守护程序配置,网络时间同步,日志转发和名称解析。</p><p>Systemd 是 Linux 系统工具,用来启动守护进程,目前已成为大多数发行版的标准配置。但在历史上,Linux 的启动一直采用 init 进程,用下面的命令启动服务:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo /etc/init.d/apache2 start<br>service apache2 start<br></code></pre></td></tr></table></figure><p>这种方法有两个缺点:</p><ul><li>一是启动时间长。init 进程是串行启动,只有前一个进程启动完,才会启动下一个进程。</li><li>二是启动脚本复杂。init 进程只是执行启动脚本,不管其他事情,脚本需要自己处理各种情况,这往往使得脚本变得很长。</li></ul><h2 id="2-争议"><a href="#2-争议" class="headerlink" title="2 争议"></a>2 争议</h2><ul><li><p>优势</p><ol><li>手册文档详细。</li><li>统一用<code>/etc/os-release</code>文件区分各个 Linux 发行版。</li><li>systemd 本来是一个先进的 init 程序,除了管理 daemon 之外,还实现了 socket-activation 来支持按需加载服务。就架构上来说完胜现有的任何系统上的任何服务管理体系。</li><li>启动速度相比与其他 init 程序,会稍快一些。</li><li>迭代迅速,新功能增加很快。</li></ol></li><li><p>争议点</p><ol><li>不遵循 UNIX 原则。UNIX 的哲学是做一件事,并且把它做好,而 systemd 则是把 pid 1 扩张到最大化。</li><li>systemd 在设计之初就不考虑 Linux 以外的平台,不遵循 POSIX 标准,而且很多功能根本就是 Linux 特有的,无法移植到 Linux 之外的平台,这尤其让 BSD 爱好者们很受伤,在 Debian 7 以前,一直维护着 Linux 和 FreeBSD 两个内核,只不过后者没什么人用,Debian 8 为了支持 systemd 不得不放弃支持 Debian kFreeBSD。</li><li>接管了太多设施,如 syslog 被 systemd-journal 取代,crond 也被 systemd 的 timer 单元取代,udev 也准备集成到 systemd 中来,未来甚至还可能取代 /etc/fstab。尽管这些新的服务大部分都是独立于主进程的,但是还是有整个系统被红帽控制住的感觉(systemd 的作者 Lennart Poettering 就职于红帽,systemd 也主要是红帽的 Fedora 首先在推,OpenSUSE 后面跟随)。这在开源社区看来是件政治不正确的事情。</li><li>有人怀疑 systemd 的可靠程度,然后就是很多管理员以前积攒的脚本全报废了(这也是管理员反对的主因吧)。</li><li>systemd 的作者是 Lennart Poettering,其主要的三个项目是 avahi, PulseAudio, systemd。他和他的小伙伴有这样的特点<ul><li>生产力极高。systemd 以不可思议的速度刷版本号,而且每次更新都有新功能。Linux 的核心服务大部分都很有年头了,systemd 的开发节奏和它们反差甚大。</li><li>代码质量不高。PulseAudio 和 systemd 初期都有巨量的 bug,经过很长时间才达到稳定。对于 systemd 这显然不符合人们的期望。Init 应该由 Linus 这样的靠谱程序员而不是 Poettering 这种傻逼程序员负责。</li><li>频繁变更设计和接口。systemd 的新功能,最好都等几个版本再用。因为 Poettering 似乎是喜欢让用户的实践去打磨他的设计的。</li><li>不考虑向后兼容。Poettering 和小伙伴们有着极端的“只用正确的方法做事”的态度。如果某个用法过去可以工作,但不符合他们心目中“正确的方式”,他们会在新版本中毫不犹豫地将你 break 掉。这种态度屡次遭到 Linus 痛骂(由于 udev 和内核紧密集成)。很多人不喜欢这种以飞速不断生产 bug 和不成熟设计的风格。实际上这更接近商业软件公司(比如微软)的开发风格,而这显然也会招黑。</li></ul></li><li>systemd 极端地奉行“只考虑 Linux”,不接受任何改进非 Linux 系统兼容性的 patch。由于 systemd 项目合并了 udev, logind 等基础设施,以及 Gnome/KDE 积极与 systemd 集成,这给其它开源内核的桌面用户(以及 Debian 这样的多内核发行版)造成了困扰。</li><li>对比 sysvinit,系统管理员不喜欢 systemd:<ul><li>systemd 是用 C 而不是系统管理员熟悉的 shell 写成。</li><li>systemd 的核心是单个 binary,而不是一堆脚本和小程序拼凑而成,不符合所谓 The Unix Way。</li><li>喜欢重新发明轮子。systemd 重新发明了一堆历史悠久的核心服务(通常是简化功能和配置):syslog, ntp, cron, fstab, dhcpcd, vt… 系统管理员更信赖他们熟悉的服务(尽管配置较为复杂)。而重新发明轮子总体上在开源社区是不被赞许的。</li></ul></li></ol></li></ul><h2 id="3-概述"><a href="#3-概述" class="headerlink" title="3 概述"></a>3 概述</h2><p>Systemd 就是的设计目标是,为系统的启动和管理提供一套完整的解决方案。根据 Linux 惯例,字母 d 是守护进程(daemon)的缩写。 Systemd 这个名字的含义,就是它要守护整个系统。使用了 Systemd,就不需要再用 init 了。Systemd 取代了 initd,成为系统的第一个进程(PID 等于 1),其他进程都是它的子进程。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">systemctl --version <span class="hljs-comment"># 查看 Systemd 的版本</span><br></code></pre></td></tr></table></figure><p>Systemd 的优点是功能强大,使用方便,缺点是体系庞大,非常复杂。事实上,现在还有很多人反对使用 Systemd,理由就是它过于复杂,与操作系统的其他部分强耦合,违反 “keep simple, keep stupid” 的 Unix 哲学。</p><p><img src="/linux/systemd/images/systemd-architecture.png" alt="Systemd-Architecture"></p><h2 id="4-系统管理"><a href="#4-系统管理" class="headerlink" title="4 系统管理"></a>4 系统管理</h2><p>Systemd 并不是一个命令,而是一组命令,涉及到系统管理的方方面面。</p><h3 id="4-1-systemctl"><a href="#4-1-systemctl" class="headerlink" title="4.1 systemctl"></a>4.1 systemctl</h3><p><code>systemctl</code> 是 Systemd 的主要命令,用于管理系统。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo systemctl reboot <span class="hljs-comment"># 重启系统</span><br>sudo systemctl poweroff <span class="hljs-comment"># 关闭系统,切断电源</span><br>sudo systemctl halt <span class="hljs-comment"># CPU 停止工作</span><br>sudo systemctl <span class="hljs-built_in">suspend</span> <span class="hljs-comment"># 暂停系统</span><br>sudo systemctl hibernate <span class="hljs-comment"># 让系统进入冬眠状态</span><br>sudo systemctl hybrid-sleep <span class="hljs-comment"># 让系统进入交互式休眠状态</span><br>sudo systemctl rescue <span class="hljs-comment"># 启动进入救援状态(单用户状态)</span><br></code></pre></td></tr></table></figure><h3 id="4-2-systemd-analyze"><a href="#4-2-systemd-analyze" class="headerlink" title="4.2 systemd-analyze"></a>4.2 systemd-analyze</h3><p><code>systemd-analyze</code> 命令用于查看启动耗时。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs bash">systemd-analyze <span class="hljs-comment"># 查看启动耗时</span><br>systemd-analyze blame <span class="hljs-comment"># 查看每个服务的启动耗时</span><br>systemd-analyze critical-chain <span class="hljs-comment"># 显示瀑布状的启动过程流</span><br>systemd-analyze critical-chain atd.service <span class="hljs-comment"># 显示指定服务的启动流</span><br></code></pre></td></tr></table></figure><h3 id="4-3-hostnamectl"><a href="#4-3-hostnamectl" class="headerlink" title="4.3 hostnamectl"></a>4.3 hostnamectl</h3><p><code>hostnamectl</code> 命令用于查看当前主机的信息。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">hostnamectl <span class="hljs-comment"># 显示当前主机的信息</span><br>sudo hostnamectl set-hostname xxx <span class="hljs-comment"># 设置主机名</span><br></code></pre></td></tr></table></figure><h3 id="4-4-localectl"><a href="#4-4-localectl" class="headerlink" title="4.4 localectl"></a>4.4 localectl</h3><p><code>localectl</code> 命令用于查看本地化设置。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">localectl <span class="hljs-comment"># 查看本地化设置</span><br>sudo localectl set-locale LANG=en_GB.utf8 <span class="hljs-comment"># 设置本地化参数</span><br>sudo localectl set-keymap en_GB<br></code></pre></td></tr></table></figure><h3 id="4-5-timedatectl"><a href="#4-5-timedatectl" class="headerlink" title="4.5 timedatectl"></a>4.5 timedatectl</h3><p><code>timedatectl</code> 命令用于查看当前时区设置。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs bash">timedatectl <span class="hljs-comment"># 查看当前时区设置</span><br>timedatectl list-timezones <span class="hljs-comment"># 显示所有可用的时区</span><br>sudo timedatectl set-timezone America/New_York <span class="hljs-comment"># 设置当前时区</span><br>sudo timedatectl set-time YYYY-MM-DD<br>sudo timedatectl set-time HH:MM:SS<br></code></pre></td></tr></table></figure><h3 id="4-6-loginctl"><a href="#4-6-loginctl" class="headerlink" title="4.6 loginctl"></a>4.6 loginctl</h3><p><code>loginctl</code> 命令用于查看当前登录的用户。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">loginctl list-sessions <span class="hljs-comment"># 列出当前 session</span><br>loginctl list-users <span class="hljs-comment"># 列出当前登录用户</span><br>loginctl show-user ruanyf <span class="hljs-comment"># 列出显示指定用户的信息</span><br></code></pre></td></tr></table></figure><h2 id="5-Unit"><a href="#5-Unit" class="headerlink" title="5 Unit"></a>5 Unit</h2><p>Systemd 可以管理所有系统资源,不同的资源统称为 Unit(单位)。</p><h3 id="5-1-Unit-种类"><a href="#5-1-Unit-种类" class="headerlink" title="5.1 Unit 种类"></a>5.1 Unit 种类</h3><p>Unit 一共分成 12 种。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs bash">Service unit <span class="hljs-comment"># 系统服务</span><br>Target unit <span class="hljs-comment"># 多个 Unit 构成的一个组</span><br>Device Unit <span class="hljs-comment"># 硬件设备</span><br>Mount Unit <span class="hljs-comment"># 文件系统的挂载点</span><br>Automount Unit <span class="hljs-comment"># 自动挂载点</span><br>Path Unit <span class="hljs-comment"># 文件或路径</span><br>Scope Unit <span class="hljs-comment"># 不是由 Systemd 启动的外部进程</span><br>Slice Unit <span class="hljs-comment"># 进程组</span><br>Snapshot Unit <span class="hljs-comment"># Systemd 快照,可以切回某个快照</span><br>Socket Unit <span class="hljs-comment"># 进程间通信的 socket</span><br>Swap Unit <span class="hljs-comment"># swap 文件</span><br>Timer Unit <span class="hljs-comment"># 定时器</span><br></code></pre></td></tr></table></figure><p><code>systemctl list-units</code> 命令可以查看当前系统的所有 Unit 。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs bash">systemctl list-units <span class="hljs-comment"># 列出正在运行的 Unit</span><br>systemctl list-units --all <span class="hljs-comment"># 列出所有 Unit,包括没有找到配置文件的或者启动失败的</span><br>systemctl list-units --all --state=inactive <span class="hljs-comment"># 列出所有没有运行的 Unit</span><br>systemctl list-units --failed <span class="hljs-comment"># 列出所有加载失败的 Unit</span><br>systemctl list-units --<span class="hljs-built_in">type</span>=service <span class="hljs-comment"># 列出所有正在运行的、类型为 service 的 Unit</span><br></code></pre></td></tr></table></figure><h3 id="5-2-Unit-状态"><a href="#5-2-Unit-状态" class="headerlink" title="5.2 Unit 状态"></a>5.2 Unit 状态</h3><p><code>systemctl status</code> 命令用于查看系统状态和单个 Unit 的状态。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">systemctl status <span class="hljs-comment"># 显示系统状态</span><br>sysystemctl status bluetooth.service <span class="hljs-comment"># 显示单个 Unit 的状态</span><br>systemctl -H [email protected] status httpd.service <span class="hljs-comment"># 显示远程主机的某个 Unit 的状态</span><br></code></pre></td></tr></table></figure><p>除了 <code>systemctl</code> 命令,status 还提供了三个查询状态的简单方法,主要供脚本内部的判断语句使用。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo systemctl is-active application.service <span class="hljs-comment"># 显示某个 Unit 是否正在运行</span><br>sudo systemctl is-failed application.service <span class="hljs-comment"># 显示某个 Unit 是否处于启动失败状态</span><br>sudo systemctl is-enabled application.service <span class="hljs-comment"># 显示某个 Unit 服务是否建立了启动链接</span><br></code></pre></td></tr></table></figure><h3 id="5-3-Unit-管理"><a href="#5-3-Unit-管理" class="headerlink" title="5.3 Unit 管理"></a>5.3 Unit 管理</h3><p>对于用户来说,最常用的是下面这些命令,用于启动和停止 Unit(主要是 service)。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo systemctl start apache.service <span class="hljs-comment"># 立即启动一个服务</span><br>sudo systemctl stop apache.service <span class="hljs-comment"># 立即停止一个服务</span><br>sudo systemctl restart apache.service <span class="hljs-comment"># 重启一个服务</span><br>sudo systemctl <span class="hljs-built_in">kill</span> apache.service <span class="hljs-comment"># 杀死一个服务的所有子进程</span><br>sudo systemctl reload apache.service <span class="hljs-comment"># 重新加载一个服务的配置文件</span><br>sudo systemctl daemon-reload <span class="hljs-comment"># 重载所有修改过的配置文件</span><br>sudo systemctl show httpd.service <span class="hljs-comment"># 显示某个 Unit 的所有底层参数</span><br>sudo systemctl show -p CPUShares httpd.service <span class="hljs-comment"># 显示某个 Unit 的指定属性的值</span><br>sudo systemctl set-property httpd.service CPUShares=500 <span class="hljs-comment"># 设置某个 Unit 的指定属性</span><br></code></pre></td></tr></table></figure><h3 id="5-4-依赖关系"><a href="#5-4-依赖关系" class="headerlink" title="5.4 依赖关系"></a>5.4 依赖关系</h3><p>Unit 之间存在依赖关系:A 依赖于 B,就意味着 Systemd 在启动 A 的时候,同时会去启动 B。有些依赖是 Target 类型(详见下文),默认不会展开显示。如果要展开 Target,就需要使用 –all 参数。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">systemctl list-dependencies --all xxx <span class="hljs-comment"># 命令列出一个 Unit 的所有依赖。</span><br></code></pre></td></tr></table></figure><h2 id="6-Target"><a href="#6-Target" class="headerlink" title="6 Target"></a>6 Target</h2><p>启动计算机的时候,需要启动大量的 Unit。如果每一次启动,都要一一写明本次启动需要哪些 Unit,显然非常不方便。Systemd 的解决方案就是 Target。<br>简单说,Target 就是一个 Unit 组,包含许多相关的 Unit 。启动某个 Target 的时候,Systemd 就会启动里面所有的 Unit。从这个意义上说,Target 这个概念类似于”状态点”,启动某个 Target 就好比启动到某种状态。<br>传统的 init 启动模式里面,有 RunLevel 的概念,跟 Target 的作用很类似。不同的是,RunLevel 是互斥的,不可能多个 RunLevel 同时启动,但是多个 Target 可以同时启动。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs bash">systemctl list-unit-files --<span class="hljs-built_in">type</span>=target <span class="hljs-comment"># 查看当前系统的所有 Target</span><br>systemctl list-dependencies multi-user.target <span class="hljs-comment"># 查看一个 Target 包含的所有 Unit</span><br>systemctl get-default<span class="hljs-comment"># 查看启动时的默认 Target</span><br>sudo systemctl set-default multi-user.target <span class="hljs-comment"># 设置启动时的默认 Target</span><br><span class="hljs-comment"># 切换 Target 时,默认不关闭前一个 Target 启动的进程,systemctl isolate 命令改变这种行为</span><br>sudo systemctl isolate multi-user.target <span class="hljs-comment"># 关闭前一个 Target 里面所有不属于后一个 Target 的进程</span><br></code></pre></td></tr></table></figure><h2 id="7-日志管理"><a href="#7-日志管理" class="headerlink" title="7 日志管理"></a>7 日志管理</h2><p>Systemd 统一管理所有 Unit 的启动日志。带来的好处就是,可以只用 journalctl 一个命令,查看所有日志(内核日志和应用日志)。日志的配置文件是 /etc/systemd/journald.conf。journalctl 功能强大,用法非常多。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo journalctl <span class="hljs-comment"># 查看所有日志(默认情况下 ,只保存本次启动的日志)</span><br>sudo journalctl -k <span class="hljs-comment"># 查看内核日志(不显示应用日志)</span><br>sudo journalctl -b <span class="hljs-comment"># 查看系统本次启动的日志</span><br>sudo journalctl -b -0<br>sudo journalctl -b -1 <span class="hljs-comment"># 查看上一次启动的日志(需更改设置)</span><br>sudo journalctl --since=<span class="hljs-string">"2012-10-30 18:17:16"</span> <span class="hljs-comment"># 查看指定时间的日志</span><br>sudo journalctl --since <span class="hljs-string">"20 min ago"</span><br>sudo journalctl --since yesterday<br>sudo journalctl --since <span class="hljs-string">"2015-01-10"</span> --<span class="hljs-keyword">until</span> <span class="hljs-string">"2015-01-11 03:00"</span><br>sudo journalctl --since 09:00 --<span class="hljs-keyword">until</span> <span class="hljs-string">"1 hour ago"</span><br>sudo journalctl -n <span class="hljs-comment"># 显示尾部的最新 10 行日志</span><br>sudo journalctl -n 20 <span class="hljs-comment"># 显示尾部指定行数的日志</span><br>sudo journalctl -f <span class="hljs-comment"># 实时滚动显示最新日志</span><br>sudo journalctl /usr/lib/systemd/systemd <span class="hljs-comment"># 查看指定服务的日志</span><br>sudo journalctl _PID=1 <span class="hljs-comment"># 查看指定进程的日志</span><br>sudo journalctl /usr/bin/bash <span class="hljs-comment"># 查看某个路径的脚本的日志</span><br>sudo journalctl _UID=33 --since today <span class="hljs-comment"># 查看指定用户的日志</span><br>sudo journalctl -u nginx.service <span class="hljs-comment"># 查看某个 Unit 的日志</span><br>sudo journalctl -u nginx.service --since today<br>sudo journalctl -u nginx.service -f <span class="hljs-comment"># 实时滚动显示某个 Unit 的最新日志</span><br>sudo journalctl -u nginx.service -u php-fpm.service --since today <span class="hljs-comment"># 合并显示多个 Unit 的日志</span><br><span class="hljs-comment"># 查看指定优先级(及其以上级别)的日志,共有 8 级</span><br><span class="hljs-comment"># 0: emerg</span><br><span class="hljs-comment"># 1: alert</span><br><span class="hljs-comment"># 2: crit</span><br><span class="hljs-comment"># 3: err</span><br><span class="hljs-comment"># 4: warning</span><br><span class="hljs-comment"># 5: notice</span><br><span class="hljs-comment"># 6: info</span><br><span class="hljs-comment"># 7: debug</span><br>sudo journalctl -p err -b<br>sudo journalctl --no-pager <span class="hljs-comment"># 日志默认分页输出,--no-pager 改为正常的标准输出</span><br>sudo journalctl -b -u nginx.service -o json <span class="hljs-comment"># 以 JSON 格式(单行)输出</span><br>sudo journalctl -b -u nginx.serviceqq -o json-pretty <span class="hljs-comment"># 以 JSON 格式(多行)输出,可读性更好</span><br>sudo journalctl --disk-usage <span class="hljs-comment"># 显示日志占据的硬盘空间</span><br>sudo journalctl --vacuum-size=1G <span class="hljs-comment"># 指定日志文件占据的最大空间</span><br>sudo journalctl --vacuum-time=1years <span class="hljs-comment"># 指定日志文件保存多久</span><br></code></pre></td></tr></table></figure><h2 id="8-参考文献"><a href="#8-参考文献" class="headerlink" title="8 参考文献"></a>8 参考文献</h2><ul><li><a href="https://wiki.debian.org/Debate/initsystem/systemd">debian.org</a></li><li><a href="https://www.freedesktop.org/wiki/Software/systemd/">freedesktop.org</a></li><li><a href="http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html">Systemd 入门教程</a></li></ul>]]></content>
<categories>
<category>linux</category>
</categories>
<tags>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title>Mirrors</title>
<link href="/linux/mirrors/"/>
<url>/linux/mirrors/</url>
<content type="html"><![CDATA[<!--- [Sites](#sites)- [Debian](#debian)- [Ubuntu](#ubuntu)- [OpenEuler](#openeuler)--><h2 id="Sites"><a href="#Sites" class="headerlink" title="Sites"></a>Sites</h2><p><a href="http://mirrors.163.com/">http://mirrors.163.com</a><br><a href="http://mirrors.aliyun.com/">http://mirrors.aliyun.com</a><br><a href="http://mirrors.tencent.com/">http://mirrors.tencent.com</a><br><a href="http://mirrors.huaweicloud.com/">http://mirrors.huaweicloud.com</a></p><p><a href="http://mirrors.tuna.tsinghua.edu.cn/">http://mirrors.tuna.tsinghua.edu.cn</a><br><a href="http://mirrors.ustc.edu.cn/">http://mirrors.ustc.edu.cn</a><br><a href="http://mirror.sjtu.edu.cn/">http://mirror.sjtu.edu.cn</a><br><a href="http://mirror.nju.edu.cn/">http://mirror.nju.edu.cn</a><br><a href="http://mirrors.bfsu.edu.cn/">http://mirrors.bfsu.edu.cn</a><br><a href="http://mirror.nyist.edu.cn/">http://mirror.nyist.edu.cn</a><br><a href="http://mirrors.neusoft.edu.cn/">http://mirrors.neusoft.edu.cn</a></p><p><a href="http://mirror.bizflycloud.vn/">http://mirror.bizflycloud.vn</a><br><a href="http://mirror.applebred.net/">http://mirror.applebred.net</a><br><a href="http://tw1.mirror.blendbyte.net/">http://tw1.mirror.blendbyte.net</a></p><p><a href="http://debian.csie.ntu.edu.tw/">http://debian.csie.ntu.edu.tw</a><br><a href="http://debian.cs.nycu.edu.tw/">http://debian.cs.nycu.edu.tw</a></p><h2 id="Debian"><a href="#Debian" class="headerlink" title="Debian"></a>Debian</h2><p><a href="https://www.debian.org/mirror/list.zh-cn.html">Debian 全球镜像站</a></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># stable</span><br>deb http://deb.debian.org/debian/ stable main contrib non-free non-free-firmware<br>deb-src http://deb.debian.org/debian/ stable main contrib non-free non-free-firmware<br>deb http://deb.debian.org/debian/ stable-updates main contrib non-free non-free-firmware<br>deb-src http://deb.debian.org/debian/ stable-updates main contrib non-free non-free-firmware<br>deb http://ftp.debian.org/debian/ stable-backports main contrib non-free non-free-firmware<br>deb-src http://ftp.debian.org/debian/ stable-backports main contrib non-free non-free-firmware<br>deb http://security.debian.org/debian-security/ stable-security main contrib non-free non-free-firmware<br>deb-src http://security.debian.org/debian-security/ stable-security main contrib non-free non-free-firmware<br></code></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># stable</span><br>deb http://ftp.cn.debian.org/debian/ stable main contrib non-free non-free-firmware<br>deb-src http://ftp.cn.debian.org/debian/ stable main contrib non-free non-free-firmware<br>deb http://ftp.cn.debian.org/debian/ stable-updates main contrib non-free non-free-firmware<br>deb-src http://ftp.cn.debian.org/debian/ stable-updates main contrib non-free non-free-firmware<br>deb http://ftp.cn.debian.org/debian/ stable-backports main contrib non-free non-free-firmware<br>deb-src http://ftp.cn.debian.org/debian/ stable-backports main contrib non-free non-free-firmware<br>deb http://ftp.cn.debian.org/debian-security/ stable-security main contrib non-free non-free-firmware<br>deb-src http://ftp.cn.debian.org/debian-security/ stable-security main contrib non-free non-free-firmware<br></code></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># Debian 12.2, or bookworm</span><br>deb http://ftp.cn.debian.org/debian/ bookworm main contrib non-free non-free-firmware<br>deb-src https://ftp.cn.debian.org/debian/ bookworm main contrib non-free non-free-firmware<br>deb http://ftp.cn.debian.org/debian/ bookworm-updates main contrib non-free non-free-firmware<br>deb-src https://ftp.cn.debian.org/debian/ bookworm-updates main contrib non-free non-free-firmware<br>deb http://ftp.cn.debian.org/debian/ bookworm-backports main contrib non-free non-free-firmware<br>deb-src https://ftp.cn.debian.org/debian/ bookworm-backports main contrib non-free non-free-firmware<br>deb http://ftp.cn.debian.org/debian-security/ bookworm-security main contrib non-free non-free-firmware<br>deb-src https://ftp.cn.debian.org/debian-security/ bookworm-security main contrib non-free non-free-firmware<br></code></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># Debian 11.8, or bullseye</span><br>deb http://ftp.cn.debian.org/debian/ bullseye main contrib non-free non-free-firmware<br>deb-src https://ftp.cn.debian.org/debian/ bullseye main contrib non-free non-free-firmware<br>deb http://ftp.cn.debian.org/debian/ bullseye-updates main contrib non-free non-free-firmware<br>deb-src https://ftp.cn.debian.org/debian/ bullseye-updates main contrib non-free non-free-firmware<br>deb http://ftp.cn.debian.org/debian/ bullseye-backports main contrib non-free non-free-firmware<br>deb-src https://ftp.cn.debian.org/debian/ bullseye-backports main contrib non-free non-free-firmware<br>deb http://ftp.cn.debian.org/debian-security/ bullseye-security main contrib non-free non-free-firmware<br>deb-src https://ftp.cn.debian.org/debian-security/ bullseye-security main contrib non-free non-free-firmware<br></code></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># Debian 10.13, or buster</span><br>deb http://ftp.cn.debian.org/debian/ buster main contrib non-free non-free-firmware<br>deb-src https://ftp.cn.debian.org/debian/ buster main contrib non-free non-free-firmware<br>deb http://ftp.cn.debian.org/debian/ buster-updates main contrib non-free non-free-firmware<br>deb-src https://ftp.cn.debian.org/debian/ buster-updates main contrib non-free non-free-firmware<br>deb http://ftp.cn.debian.org/debian/ buster-backports main contrib non-free non-free-firmware<br>deb-src https://ftp.cn.debian.org/debian/ buster-backports main contrib non-free non-free-firmware<br>deb http://ftp.cn.debian.org/debian-security/ buster-security main contrib non-free non-free-firmware<br>deb-src https://ftp.cn.debian.org/debian-security/ buster-security main contrib non-free non-free-firmware<br></code></pre></td></tr></table></figure><h2 id="Ubuntu"><a href="#Ubuntu" class="headerlink" title="Ubuntu"></a>Ubuntu</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># Ubuntu Noble 24.04, devel</span><br>deb http://archive.ubuntu.com/ubuntu/ devel main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ devel main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ devel-updates main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ devel-updates main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ devel-backports main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ devel-backports main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ devel-security main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ devel-security main multiverse restricted universe<br></code></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># Ubuntu Noble 24.04</span><br>deb http://archive.ubuntu.com/ubuntu/ noble main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ noble main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ noble-updates main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ noble-updates main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ noble-backports main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ noble-backports main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ noble-security main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ noble-security main multiverse restricted universe<br></code></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># Ubuntu Mantic 23.10</span><br>deb http://archive.ubuntu.com/ubuntu/ mantic main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ mantic main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ mantic-updates main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ mantic-updates main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ mantic-backports main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ mantic-backports main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ mantic-security main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ mantic-security main multiverse restricted universe<br></code></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># Ubuntu Lunar 23.04</span><br>deb http://archive.ubuntu.com/ubuntu/ lunar main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ lunar main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ lunar-updates main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ lunar-updates main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ lunar-backports main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ lunar-backports main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ lunar-security main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ lunar-security main multiverse restricted universe<br></code></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># Ubuntu Jammy 22.04</span><br>deb http://archive.ubuntu.com/ubuntu/ jammy main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ jammy main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ jammy-updates main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ jammy-updates main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ jammy-backports main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ jammy-backports main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ jammy-security main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ jammy-security main multiverse restricted universe<br></code></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># Ubuntu Focal 20.04</span><br>deb http://archive.ubuntu.com/ubuntu/ focal main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ focal main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ focal-updates main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ focal-updates main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ focal-backports main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ focal-backports main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ focal-security main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ focal-security main multiverse restricted universe<br></code></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># Ubuntu Bionic 18.04</span><br>deb http://archive.ubuntu.com/ubuntu/ bionic main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ bionic main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ bionic-updates main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ bionic-updates main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ bionic-backports main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ bionic-backports main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ bionic-security main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ bionic-security main multiverse restricted universe<br></code></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># Ubuntu Xenial 16.04</span><br>deb http://archive.ubuntu.com/ubuntu/ xenial main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ xenial main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ xenial-updates main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ xenial-updates main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ xenial-backports main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ xenial-backports main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ xenial-security main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ xenial-security main multiverse restricted universe<br></code></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># Ubuntu Trusty 14.04</span><br>deb http://archive.ubuntu.com/ubuntu/ trusty main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ trusty main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ trusty-updates main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ trusty-updates main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ trusty-backports main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ trusty-backports main multiverse restricted universe<br>deb http://archive.ubuntu.com/ubuntu/ trusty-security main multiverse restricted universe<br>deb-src http://archive.ubuntu.com/ubuntu/ trusty-security main multiverse restricted universe<br></code></pre></td></tr></table></figure><h2 id="OpenEuler"><a href="#OpenEuler" class="headerlink" title="OpenEuler"></a>OpenEuler</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># OpenEuler 20.03 LTS</span><br>[OS]<br>name=OS<br>baseurl=http://mirrors.aliyun.com/openeuler/openEuler-20.03-LTS/OS/<span class="hljs-variable">$basearch</span>/<br>enabled=1<br>gpgcheck=0<br>gpgkey=http://mirrors.aliyun.com/openeuler/openEuler-20.03-LTS/OS/<span class="hljs-variable">$basearch</span>/RPM-GPG-KEY-openEuler<br><br>[everything]<br>name=everything<br>baseurl=http://mirrors.aliyun.com/openeuler/openEuler-20.03-LTS/everything/<span class="hljs-variable">$basearch</span>/<br>enabled=1<br>gpgcheck=0<br>gpgkey=http://mirrors.aliyun.com/openeuler/openEuler-20.03-LTS/everything/<span class="hljs-variable">$basearch</span>/RPM-GPG-KEY-openEuler<br><br>[EPOL]<br>name=EPOL<br>baseurl=http://mirrors.aliyun.com/openeuler/openEuler-20.03-LTS/EPOL/<span class="hljs-variable">$basearch</span>/<br>enabled=1<br>gpgcheck=0<br>gpgkey=http://mirrors.aliyun.com/openeuler/openEuler-20.03-LTS/OS/<span class="hljs-variable">$basearch</span>/RPM-GPG-KEY-openEuler<br><br>[debuginfo]<br>name=debuginfo<br>baseurl=http://mirrors.aliyun.com/openeuler/openEuler-20.03-LTS/debuginfo/<span class="hljs-variable">$basearch</span>/<br>enabled=1<br>gpgcheck=0<br>gpgkey=http://mirrors.aliyun.com/openeuler/openEuler-20.03-LTS/debuginfo/<span class="hljs-variable">$basearch</span>/RPM-GPG-KEY-openEuler<br><br>[<span class="hljs-built_in">source</span>]<br>name=<span class="hljs-built_in">source</span><br>baseurl=http://mirrors.aliyun.com/openeuler/openEuler-20.03-LTS/source/<br>enabled=1<br>gpgcheck=0<br>gpgkey=http://mirrors.aliyun.com/openeuler/openEuler-20.03-LTS/source/RPM-GPG-KEY-openEuler<br><br>[update]<br>name=update<br>baseurl=http://mirrors.aliyun.com/openeuler/openEuler-20.03-LTS/update/<span class="hljs-variable">$basearch</span>/<br>enabled=1<br>gpgcheck=0<br>gpgkey=http://mirrors.aliyun.com/openeuler/openEuler-20.03-LTS/OS/<span class="hljs-variable">$basearch</span>/RPM-GPG-KEY-openEuler<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>linux</category>
</categories>
<tags>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title>SSH</title>
<link href="/tools/ssh/"/>
<url>/tools/ssh/</url>
<content type="html"><![CDATA[<h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><p>系统级配置文件路径<code>/etc/ssh/sshd_config</code><br>用户级配置文件路径<code>~/.ssh/config</code></p><h2 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h2><p>常用命令:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 登录远程主机</span><br>ssh user@host<br><span class="hljs-comment"># 如果本地用户名与远程用户名一致,登录时可以省略用户名</span><br>ssh host<br><span class="hljs-comment"># 默认端口是22,使用参数指定端口</span><br>ssh -p 2222 user@host<br><span class="hljs-comment"># 生成密钥</span><br>ssh-keygen -t rsa -C <span class="hljs-string">"comment"</span><br><span class="hljs-comment"># 将公钥拷贝到远程主机</span><br>ssh-copy-id user@host<br>ssh-copy-id -i ~/.ssh/id_rsa.pub user@host <span class="hljs-comment"># 指定公钥文件</span><br><span class="hljs-comment"># 重启服务</span><br>service ssh restart<br></code></pre></td></tr></table></figure><p>编辑<code>~/.ssh/config</code>:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># github</span><br>Host GitHub<br>HostName github.com<br>PreferredAuthentications publickey<br>IdentityFile ~/.ssh/id_rsa_github<br><span class="hljs-comment"># gitlab</span><br>Host GitLab<br>HostName gitlab.com<br>Port 36000<br>PreferredAuthentications publickey<br>IdentityFile ~/.ssh/id_rsa_gitlab<br></code></pre></td></tr></table></figure><p><code>Host</code>可用于<code>HostName</code>的别称,<code>git clone [email protected]/aaa/bbb.git</code>可替换为<code>git clone git@GitHub/aaa/bbb.git</code>。<br><code>Port</code>可省略设置端口号,<code>ssh -p 36000 git@Github</code>简写为<code>ssh git@Github</code>。</p><p>默认情况下只会读取 id_rsa 文件,如果想将二个公钥 github、gitlab 一起读取需要使用命令:<code>ssh-add ~/.ssh/id_rsa_github</code>(gitlab 同理)可以使用<code>ssh-add -l</code>查看秘钥,在 Windows 中需要执行<code>ssh-add ~/.ssh/id_rsa_gitlab</code>命令。</p><p>在 Windows 中提示“Could not open a connection to your authentication agent.”,执行<code>ssh-agent bash</code>即可。</p><h2 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h2><ul><li><a href="https://www.ruanyifeng.com/blog/2011/12/ssh_remote_login.html">SSH 原理与运用(一):远程登录</a></li><li><a href="https://www.ruanyifeng.com/blog/2011/12/ssh_port_forwarding.html">SSH 原理与运用(二):远程操作与端口转发</a></li><li><a href="https://imququ.com/post/multiple-ssh-keys-with-different-hosts.html">针对不同主机使用不同 SSH Key</a></li></ul>]]></content>
<categories>
<category>tools</category>
</categories>
<tags>
<tag>Tool</tag>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title>Hello World</title>
<link href="/uncategorized/hello-world/"/>
<url>/uncategorized/hello-world/</url>
<content type="html"><![CDATA[<p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p><h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">hexo new <span class="hljs-string">"My New Post"</span><br></code></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/writing.html">Writing</a></p><h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">hexo server<br></code></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/server.html">Server</a></p><h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">hexo generate<br></code></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/generating.html">Generating</a></p><h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">hexo deploy<br></code></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/one-command-deployment.html">Deployment</a></p>]]></content>
</entry>
</search>