小众的常量迭代器

这个新特征其实是偶尔在别人的总结中看到的,但觉得确实很有趣,就做个记录:

1. 需求

我们一般在使用STL容器时,下面代码是非常常见的:

int sum = 0;
vector<int> v{1, 2, 3, 4, 5, 6};
vector<int>::iterator it = v.begin();
while(it != v.end()){
       sum += *it;
       it++;
 }

但是,如果我们一旦定义容器为常量,就必须注意迭代器也需要声明为常量:

int sum = 0;

//编译错误:原因是定义的vector是const类型,所以迭代器必须也是const类型
const vector<int> cv{1, 2, 3, 4, 5, 6};
vector<int>::iterator cit = cv.begin();
while(cit != v.end()){
       sum += *cit;
       cit++;
 }

//正确写法:
const vector<int> cv{1, 2, 3, 4, 5, 6};
vector<int>::const_iterator cit = cv.begin();
while(cit != v.end()){
       sum += *cit;
       cit++;
}

这显然很麻烦,一个简单的方法是直接使用auto来自动推断迭代器类型(想必大家都更倾向于这样,毕竟...有了auto还要啥自行车):

auto ait = cv.begin();
while(ait != cv.end()){ 
       sum += *ait;
       ait++;
 }

2. 优势

但我们也不难想到存在这样一种情形:数据本身不是const类型,但是从设计的角度来讲有些处理不应该修改该数据。这时也应该要求const类型的迭代器,以避免数据被意外修改。所以,C++11为此提供了cbegin和cend方法。

vector<int> v{1, 2, 3, 4, 5, 6};
auto ait = v.cbegin();
while(ait != v.cend()){
           sum += *ait;
           *ait = sum;  //编译错误
           ait++;
}

cbegin()/cend()决定了返回的迭代器类型为const。这时即使vector的类型不是const,也可以防止对该数据的误操作。