Skip to content

Commit 61f4d39

Browse files
authored
Update cpp_tricks.md
1 parent c7857bd commit 61f4d39

File tree

1 file changed

+113
-8
lines changed

1 file changed

+113
-8
lines changed

docs/cpp_tricks.md

+113-8
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,38 @@ bool find(const vector<int> &v, int target) {
430430
}
431431
```
432432
433+
但有时,我们的函数可能写了额外的操作,做完查找后不想直接返回。用 `return` 提前返回的话,下面 `do_final` 部分就无法执行到,只能复读一遍。
434+
435+
```cpp
436+
void find(const vector<int> &v, int target) {
437+
for (int i = 0; i < v.size(); ++i) {
438+
if (v[i] == target) {
439+
do_something();
440+
do_final();
441+
return;
442+
}
443+
}
444+
do_other();
445+
do_final();
446+
}
447+
```
448+
449+
改用 `goto` 来打断循环,又不美观了。
450+
451+
```cpp
452+
void find(const vector<int> &v, int target) {
453+
for (int i = 0; i < v.size(); ++i) {
454+
if (v[i] == target) {
455+
do_something();
456+
goto final;
457+
}
458+
}
459+
do_other();
460+
final:
461+
do_final();
462+
}
463+
```
464+
433465
可以包裹一个立即调用的 Lambda 块 `[&] { ... } ()`,限制提前返回的范围:
434466
435467
```cpp
@@ -448,47 +480,120 @@ void find(const vector<int> &v, int target) {
448480
}
449481
```
450482

483+
这样,return 最多只能打断到当前 Lambda 函数结束的位置,而不能打断整个大函数了。
484+
451485
## Lambda 复用代码
452486

487+
```cpp
488+
void calc_average() {
489+
int res = 0;
490+
int count = 0;
491+
for (int i = 0; i < cat_arr.size(); i++) {
492+
res += cat_arr[i].age;
493+
count += cat_arr[i].count;
494+
}
495+
for (int i = 0; i < dog_arr.size(); i++) {
496+
res += dog_arr[i].age;
497+
count += dog_arr[i].count;
498+
}
499+
for (int i = 0; i < pig_arr.size(); i++) {
500+
res += pig_arr[i].age;
501+
count += pig_arr[i].count;
502+
}
503+
}
504+
```
505+
506+
你是否被迫写出以上这种复读代码?大部分内容都是重复的,每次只有一小部分修改,导致不得不复读很多遍,非常恼人!
507+
508+
“设计模式”官腔的做法是额外定义一个函数,把重复的部分代码功能抽出来变成一个 `cihou` 模板函数,然后再 `calc_average` 里只需要调用三次这个 `cihou` 函数即可实现复用:
509+
510+
```cpp
511+
template <class T>
512+
void cihou(int &res, int &count, std::vector<T> const &arr) {
513+
for (int i = 0; i < arr.size(); i++) {
514+
res += arr[i].age;
515+
count += arr[i].count;
516+
}
517+
}
518+
519+
void calc_average() {
520+
int res = 0;
521+
int count = 0;
522+
cihou(res, count, cat_arr);
523+
cihou(res, count, dog_arr);
524+
cihou(res, count, pig_arr);
525+
}
526+
```
527+
528+
然而,额外定义一个函数也太大费周章了,而且还需要把所有用到的局部变量作为参数传进去!参数部分依然需要反复复读,并且还需要一个个指定所有参数的类型,写一长串模板等。最重要的是定义外部函数会污染了全局名字空间。
529+
530+
> {{ icon.fun }} 洁癖程序员:脏了我的眼!
531+
532+
使用 Lambda,就可以让你在 `calc_average` 当前函数里“就地解决”,无需定义外部函数。
533+
534+
更妙的是:Lambda 支持 `[&]` 语法,自动捕获所有用到的局部变量为引用!无需一个个传递局部变量引用作为函数参数,没有复读,更加无感。只有重复代码中真正区别的部分需要传参数。
535+
536+
```cpp
537+
void calc_average() {
538+
int res = 0;
539+
int count = 0;
540+
auto cihou = [&] { // 局部 Lambda 的好处:自动帮你捕获 res 和 count!
541+
for (int i = 0; i < arr.size(); i++) {
542+
res += arr[i].age;
543+
count += arr[i].count;
544+
}
545+
};
546+
cihou(cat_arr);
547+
cihou(dog_arr);
548+
cihou(pig_arr);
549+
}
550+
```
551+
552+
> {{ icon.tip }} 现在只有两个变量 `res``count` 可能还没什么,如果重复的部分用到一大堆变量,同时还有时候用到,有时候用不到的话,你就觉得 Lambda 好用了。
553+
554+
例如字符串切片函数典型的一种实现中,因为“尾巴”的伺候和“主体”的伺候,就会产生重复代码:
555+
453556
```cpp
454557
vector<string> spilt(string str) {
455558
vector<string> list;
456559
string last;
457560
for (char c: str) {
458561
if (c == ' ') {
459562
list.push_back(last);
460-
last.clear();
563+
last = "";
461564
} else {
462-
last.push_back(c);
565+
last += c;
463566
}
464567
}
465568
list.push_back(last);
466569
return list;
467570
}
468571
```
469572
470-
上面的代码可以用 Lambda 复用:
573+
上面的代码中重复的部分 `list.push_back(last);` 可以用 Lambda 复用,把重复的操作封装成局部的 Lambda
471574
472575
```cpp
473576
vector<string> spilt(string str) {
474577
vector<string> list;
475578
string last;
476-
auto push = [&] {
579+
auto push_last = [&] {
477580
list.push_back(last);
478-
last.clear();
581+
last = "";
479582
};
480583
for (char c: str) {
481584
if (c == ' ') {
482-
push();
585+
push_last();
483586
} else {
484-
last.push_back(c);
587+
last += c;
485588
}
486589
}
487-
push();
590+
push_last();
488591
return list;
489592
}
490593
```
491594

595+
## 打表法代替 if-else
596+
492597
## 类内静态成员 inline
493598

494599
在头文件中定义结构体的 static 成员时:

0 commit comments

Comments
 (0)