文章目录
迭代器:
1.迭代器的设计:
不管是泛型思维或是STL的实际应用,迭代器都扮演着重要的角色。
STL的中心思想:
将容器和算法分开。彼此独立设计,然后再将它们粘合在一起。
从技术角度并不困难,C++的class template和function template都可以分别达成目标。
如何设计出两者之间的良好的粘合剂,才是最大的问题。
举个例子:
利用模板函数,使得迭代器和容器之间关联。
template<typename _BI,typename _Ty>
_BI my_find(_BI _first,_BI _last,const _Ty &val)
{
cout<< typeid(_BI).name()<<endl;
for(;_first !_last;++_first)
{
if(*_first == val)
{
break;
}
}
return _first;
}
不论什么容器都可以使用该算法。
int main()
{
vector<int> vec = {12,23,34,45,56};
list<int> ilist = {12,23,34,45,56};
deque<int> deq = {12,23,34,45,56};
vector<int> ::iterator it = my_find(vec.begin(),vec.end(),34);
cout<<*it<<endl;
list<int> ::iterator il = my_find(ilist.begin(),ilist.end(),45);
cout<<*il<<endl;
deque<int> ::iterator ide = my_find(deq.begin(),deq.end(),56);
cout<<*ide<<endl;
}
2. 迭代器是一种 smart pointer
- 迭代器是一种类似指针的对象,而指针的行为。
- 最常用也最重要的是 【内容提取】和【成员访问】
意思就是主要工作由下面两个函数来实现。
_Ty &operator *() const { return pointer; }
_Ty operator ->()const {return pointer;}
3.迭代器的5种相应类型
value_type
所谓value_type ,是指迭代器所指的对象的型别。
任何一个打算和STL算法有完美搭配的class,都应该定义自己的value_type内嵌型别。
difference_type
difference_type:表示两个迭代器之间的距离.
因此它也可以用来表示一个容器的最大容量。因为对于连续空间的容器而言,头尾之间的距离就是其最大容量。
如果一个泛型算法提供计数功能,例如 STL的count(),其传回值就必须使用迭代器的difference_type;
template<typename I,typename T>
typename iterator_traits<I>::difference_type
count(I first, I last, T val)
{
iterator_traits<I>::difference_type n = 0;
for (; first != last; first++)
{
if (*first == val)
{
++n;
}
}
return n;
}
reference_type
迭代器所指之物的内容是否允许被改变?
因此迭代器分为两种:constant iterator 和 mutable iterator
当我们对mutable iterator进行提领操作,获得的不应该是右值(rvalue),而应该是左值(lvalue),因为右值不允许赋值操作,左值才允许。
pointer_type
pointers 和 references 在 C++中有非常密切的关联。如果“传回一个左值,
左值,令它代表p所指之物的,是可能的,那么“传回一个地址”也一定可以。
也就是说,我们能够传回一个pointer,指向迭代器所指之物。
示例:
Item& operator*() const { return *ptr; }
Item* operator->() const { return ptr; }
template<typename _C, typename _Ty, typename _D = ptrdiff_t,
typename _Pointer = _Ty*, typename _Reference = _Ty&>
struct iterator
{
typedef _C iterator_category; //迭代器类型
typedef _Ty value_type; //迭代器所指之物的值类型
typedef _D difference_type; //差值类型
typedef _Pointer pointer; //迭代器所指之物的引用类型
typedef _Reference reference; //迭代器所指之物的指针类型
};
iterator_category
- Input_iterator :
- 特点:只读,不写,只扫描一遍,只能递增。
- 输入迭代器可以读取序列中的元素。
输入迭代器只用于顺序访问对于一个输入迭代器,*iter++保证是有效的,但递增它可能导致所有其他指向流的迭代器失效,所以输入迭代器只能用于单遍扫描算法。
输入迭代器必须支持: - 用于比较两个迭代器相等和不相等运算符(==, !=)
- 用于推进迭代器的前置和后置递增运算符(++)
- 用于读取元素的解引用运算符(*);解引用只会出现在赋值运算符的右侧(因为输入迭代器只读不写)
- 箭头运算符(->),等价于(*it).member,即,解引用迭代器,并提取对象的成员
- Output_iterator :唯写(write only)
特点:只写,不读;单遍扫描,只能递增;
输出迭代器必须支持:
- 用于推进迭代器的前置和后置递增运算(++);
- 解引用运算符(*),只出现在赋值运算符的左侧(因为输出迭代器只写不读)(向一个已经 解引用的输出迭代器赋值,就是将值写入它所指向的元素);
我们只能向一个输出迭代器赋值一次,类似于输入迭代器,输出迭代器也只能用于单遍扫描算法
- Forward_iterator:允许“写入型”算法,正向迭代器。
特点:可读写,多遍扫描,只能递增
前向迭代器支持:
- 可以读写元素,这类迭代器只能在序列中沿一个方向移动。
- 前向迭代器支持所有输入和输出迭代器的操作,而且可以多次读写同一元素。
- 可以保存前向迭代器的状态,使用前向迭代器的算法可以对序列进行多遍扫描。
- Bidirectional_iterator:双向迭代器,某些算法需要逆向访问某个迭代器区间。
特点:可读写,多遍扫描,可能递增递减
双向迭代器支持:
- 可以正向/反向读写序列中的元素。
- 除了支持所有前向迭代器的操>作之外,双向迭代器还支持前置和后置递减运算符.
- Random_access_iterator:随机性迭代器,涵盖所有指针操作
特点:可读写,多遍扫描,支持全部迭代器运算
随机访问迭代器提供在常量时间内访问任意元素的能力。此类迭代器支持双向迭代器的所有功能此外,还支持:
- 用于比较两个迭代器相对位置的关系运算符(<,<=,>,>=)
- 迭代器和一个整数值的加减运算(+,+=,-,-=),计算结果迭代器在序列中前进(后退)给定整数个元素后的位置
- 用于两个迭代器上的减法运算符号(-),得到两个迭代器的距离
- 下标运算符(iter[n])等价于*(iter[n])
//输入迭代器标志域
struct input_iterator_tag {};
//输出迭代器标志域
struct output_iterator_tag {};
//前向迭代器标志域 继承 输入,输出迭代器的所有功能
struct forward_iterator_tag : public input_iterator_tag {};
//双向迭代器标志域 继承 前向迭代器
struct bidirectional_iterator_tag : public forward_iterator_tag {};
//随机迭代器,继承 双向迭代器
struct random_access_iterator_tag : public bidirectional_iterator_tag {};