STL迭代器(一) 初识迭代器
迭代器
我们在使用STL的时候, 我们会通过迭代器来操作容器.
它相当于一个桥梁, 是一个标准的接口.
它类似一个指针, 实现了指针的部分操作.
迭代器的种类:
- 输入迭代器
- 输出迭代器
- 前向迭代器
- 双向迭代器
- 随机迭代器
每种迭代器支持的功能不同.
本质剖析
SGI中vector的迭代器
#include <vector>
#include <iostream>
int main()
{
std::vector<int> demo;
demo.push_back(1);
demo.push_back(2);
demo.push_back(3);
demo.push_back(4);
demo.push_back(5);
std::vector<int>::iterator it;
it = demo.begin();
for (; it != demo.end(); ++it)
{
std::cout << *it << std::endl;
}
return 0;
}根据以上的小例子, 我们拿出SGI的代码, 来看一下这个迭代器.
找到iterator的定义, 如下图所示: 
可以看到, iterator是 value_type* 类型.
而value_type是我们的 _Tp由此可见, SGI中的vector里的迭代器就是一个指针.
SGI中list的迭代器
std::list<int>::iterator it;同样, 我们首先找到 iterator的定义. 
可以看到, list的iterator 和 const_iterator 都是一个模板类 _List_iterator
我们查看一下 _List_iterator 这个模板类.
可以看到, 该类重载了 operator* operator-> operator++ operator--操作符.
这是迭代器常用的操作.
不知道大家有没有一个疑问, 为什么没有 operator[] 呢? 这个问题我们先留下, 留到下节课来解答.
我们又注意到, operator++ 和 operator-- 调用了方法, 而方法在本类中没有.
然后, 我们发现这个模板类继承自 _List_iterator_base 这个类.
注意, 继承的这个类不是模板类.
我们继续跟入 _List_iterator_base 这个类.
可以看到, 这个类实现了++和--的方法.
本质上, 它们是对链表的 next 和 prev 进行访问.看到这里, 我们知道了, list的迭代器是一个类, 实现了一部分的指针操作.
Visual Studio 中的vector的迭代器
#include <vector>
int main()
{
std::vector<int>::iterator it;
return 0;
}同样的, 我们首先找到 iterator 的定义: 
我们发现, 它是隶属于 _Mybase 中的一个 iterator.
而我们的 _Mybase 是 _Vector_alloc<_Vec_base_types<_Ty, _Alloc> > 无法避免, 我们要来看一看 _Vec_base_types 是什么鬼了... 
很崩溃, 简言之, 是一些东西的包装.
看看那个长长的typedef......
总之, 这货是一个包装器.
需要注意的是, 我们的 _Wrap_alloc 是一个模板类, 是分配器中的类.
它被定义为 _Alty, 也就是分配器类型.
然后, 我们的_Val_types中就包含了 分配器 中定义的 pointer, reference 等.好的, 我们先暂时忘掉 _Vec_base_types, 看看我们的 _Vector_alloc 模板类. 
赞, 终于看到了iterator了.
可以看到iterator的原型是 _Vector_iterator<_Vector_val<_Val_types> >
我们先看一眼 _Vector_val
可以看到, _Vector_val 中定义了我们的 first, last, end
是不是和我们迭代器的 begin() end() 有点相似呢?在来看看 _Vector_iterator 这个模板类 
可以看到, 这就是我们的iterator的实现类了.
它继承自我们的 _Vector_const_iterator 类.
也就是说, iterator 继承自 const_iterator 我们还发现, vector的迭代器实现了 operator[]
Visual Studio 中的list的迭代器
跟踪方法相同, 在此不再多说, 直接给出寻找的截图. 


我们又发现, list的迭代器又没有 operator[]
总结
- 每个容器都有自己的迭代器
- 容器的迭代器的内部操作和处理是不同的
- 迭代器对外暴露的名称是相同的
不同类型的迭代器, 支持的操作不同.
- 本节课不做讨论, 留待下节课.
vector的operator=的语义问题
在SGI中, vector的iterator是一个指针, 指针可以直接赋值.
而在VS中, vector的iterator并不是一个指针, 而是一个对象.
我们查看一下 begin() 方法, 就会发现:
iterator begin() _NOEXCEPT
{ // return iterator for beginning of mutable sequence
return (iterator(this->_Myfirst(), _STD addressof(this->_Get_data())));
}它是以对象来返回的, 会构建一个iterator的临时对象.
此时, 如下例子:
#include <vector>
int main()
{
std::vector<int> demo;
std::vector<int>::iterator it;
it = demo.begin();
return 0;
}在执行 it = demo.begin() 的时候, 会调用 iterator 的默认 operator= 方法.
也就是说, 只会把_Ptr的地址拷贝到it的_Ptr中.
这是一个浅拷贝.
因为iterator指向的是我们容器中的一个元素, 这种浅拷贝的语义是正确的!
未完待续...
如有错误,请提出指正!谢谢.
本文由 花心胡萝卜 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: 2017-04-07 at 04:16 pm