从一个求和函数谈起"
有一个简单的程序,对一个整数数组求和,我们试着用几种不同的方式实现。
第一种方式 goto
int sum(int *begin, int *end) {
int ret = 0;
int *p = begin;
loop:
if (p == end) {
goto end;
}
ret = ret + *p;
p = p + 1;
goto loop;
end:
return ret;
}
第二种方式 while
int sum(int *begin, int *end) {
int ret = 0;
int *p = begin;
while (p != end) {
ret = ret + *p;
p = p + 1;
}
return ret;
}
第三种方式 for
int sum(int *begin, int *end) {
int ret = 0;
for(int *p = begin; p != end; p = p + 1){
ret = ret + *p;
}
return ret;
}
第四种方式 foreach
,需要 c++11 标准
struct range {
int * begin_;
int * end_;
int * begin() {return begin_;}
int * end() {return end_;}
};
int sum(int *begin, int *end) {
int ret = 0;
for (int x : range{begin, end}) {
ret = ret + x;
}
return ret;
}
第五种方式,accumulate
int sum(int *begin, int *end) {
return std::accumulate(begin, end, 0, std::plus<int>());
}
goto
的实现方式是最灵活的,有可能实现麻花式的流程控制。
相对 goto
来说,while
是一种固定模式的循环结构。于是while
抽象出来这种循环模式。
相对 while
来说,for
更加强调了规范的循环结构。
for-each
在 for
的基础上,加入了更多的限制,我们无法看到循环的游标变量了。某种程度上,防止了内存非法访问。
accumulate
类似的,加入更多的限制。
每种方式增加了一层抽象,逐步提高了代码的可读性。
关于性能,我们可以试着用下面的命令看一下
g++ -std=c++11 -ggdb -o a.out -Os a.cpp
如果我们使用 -Os
优化开关,五种方式生成了一模一样的汇编代码。在某些情况下,c++ 增加了代码抽象级别,提高了可读性,而且不损失性能。