从一个求和函数谈起"

有一个简单的程序,对一个整数数组求和,我们试着用几种不同的方式实现。

第一种方式 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-eachfor 的基础上,加入了更多的限制,我们无法看到循环的游标变量了。某种程度上,防止了内存非法访问。

accumulate 类似的,加入更多的限制。

每种方式增加了一层抽象,逐步提高了代码的可读性。

关于性能,我们可以试着用下面的命令看一下

g++ -std=c++11 -ggdb -o a.out -Os a.cpp

如果我们使用 -Os 优化开关,五种方式生成了一模一样的汇编代码。在某些情况下,c++ 增加了代码抽象级别,提高了可读性,而且不损失性能。