C++STL为什么要有const_iterator

这是个困扰我很久了的问题,可能一开始对面向对象的理解不够深。

刚刚想明白了,随手记录一下。


 

先从const iterator和const_iterator说起

const iterator 是iterator本身是个常量,iterator本身里面存的是指针,也就是iterator的值,也就是那个指针不能改变,也就是不能指向其他的位置,但是所指向的位置的元素是可以通过这个iterator来改变的。

const_iterator 其实本质来说,是另一个类。我们可以想象成,它的数据成员是一个指向常量元素的指针,(比如 const T*)也就是说,这个const_iterator里存着的指针是可以改变的,即可以 ++ 或 - - 操作,但是,这是一个指向常量的指针,指向的元素是常量,不可改变。

有点绕,我们再从一个例子扒一扒。

vector<int> ivec1(10);
const vector<int> ivec2(10);
vector<int>::iterator iter1 = ivec1.begin(); // true
vector<int>::iterator iter2 = ivec2.begin();  // error
vector<int>::const_iterator iter3 = ivec2.begin(); // true
vector<int>::const_iteartor iter4 = ivec1.begin();  // true

通过上面这个例子,我们就可以更直观的再深入理解一下了。
因为ivec2本身就是一个常量的vector,所以ivec2里面的元素必然是不能被改变的。如果直接定义一个iterator是会报错的,因为iterator意味着这个iterator可以遍历容器,且可以改变容器元素,显然如果容器被定义成常量了之后,这个iterator是不合理的。

所以这才有了const_iterator的出现。作为一个迭代器,遍历元素是必须要的,不然就丧失了一个迭代器的意义了。但是由于常量容器的存在,iterator不能满足这个需求。const_iteartor代表的就是不能改变容器元素,但是可以遍历容器的迭代器。

但是const_iterator不仅仅是只针对已经被声明为常量的容器用的,如果一个非常量容器,但是你不想改变容器的元素,那么也可以用const_iterator,因为里面存的是一个指向常量的指针。

最后再来看一下底层实现,更深入的扒一扒。

直接看最简单的vector容器吧,list和deque要更加复杂一些,但是本质都是一样的。(list是指向node节点的指针,duque的iterator更加复杂,因为它的内存分配是一段一段的,详情可见STL源码或者我的github www.github.com/linxiaoye/TinySTL)

/*vector的数据结构一般是这样的*/
T* start;
T* finish;
size_t n;

typedef T            value_type;
typedef T*           iterator;
typedef const T*     const_iterator;

iterator begin() { return start; }     // ①
const_iterator begin() const { return start; }  // ②
const_iterator cbegin() const { return start; }  // ③

我们可以看到,vector里面是这样实现的。
begin()有两个实现,外加一个cbegin(),有三个实现。
①就是最一般的实现,可遍历,可改变元素值。一般用于非常量容器。
②是可遍历,不可改变元素值,一般用于常量容器。当你对一个常量容器直接调用begin(),就是调用的②。调用值得一提的是,它这个不可改变元素值是全方位表现出来了的。从 typedef const T* const_iterator 开始,就限制了这是一个指向常量的指针,不可改变元素值;②中返回值是const_iterator也说明了返回的是一个存有指向常量的指针的迭代器;cosnt成员函数也说明了,不能通过这个函数来改变元素的值。
③其实跟②是几乎一样的,只是函数名不同,也就是说,当你实例化一个常量vector时,你调用begin() 和 cbegin()其实是一样的,没有区别。但是,当你定义的是一个非常量容器时,你想调用一个不能改变所指向元素的迭代器,那么就应该调用cbegin(),它可以满足你的要求。

最后总结一下 

  • iterator 可遍历,可改变所指元素
  • const_iterator 可遍历,不可改变所指元素
  • const iterator 不可遍历,可改变所指元素
  • const_iterator 主要是在容器被定义成常量、或者非常量容器但不想改变元素值的情况下使用的,而且容器被定义成常量之后,它返回的迭代器只能是const_iterator
  • begin() 与 cbegin() 其实在容器被定义成常量之后,本质上是一样的,没有区别,调用哪个都行;但是容器时非常量时,如果你不想改变元素值,就只能调用cbegin()

 

转载于:https://www.cnblogs.com/yyehl/p/yyehl.html

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值