STL迭代器
1、概念
迭代器,旨在提供一种方法,使得依次访问某容器内的各个元素,而又不需要暴露出该容器的内部表达方式。迭代器不是指针,是类模板,表现得像指针:迭代器返回额是对象引用而不是对象的值。
2、迭代器的几个型别
- 值类型
- 差值类型
- 引用类型
- 指针类型
- 迭代器类型(包括单向迭代器、随即迭代器、双向迭代器)
– [1] input_iterator;//只读迭代器
– [2] output_interator;//只写迭代器
– [3] Forward_iterator;//正向迭代器
– [4] Bidirectional_iterator;//双向迭代器
– [5] Random_Access_iterator;//随机迭代器
3、迭代器使用
以vector容器为例:
#include <iostream>
#include<vector>
using namespace std;
//模板函数
template<class _T>
void print(_T con)
{
for(typename _T::const_iterator it=con.begin();it!=con.end();++it)
{
cout<<*it<<" ";
}
cout<<endl;
}
int main()
{
//vector 随机迭代器
vector<int> vec;
for(int i=0;i<5;++i)
{
vec.push_back(i);
}
//只能读取容器中的元素,不可修改
vector<int>::const_iterator it=vec.begin();
for( ; it!=vec.end();it++)
{
cout<<*it<<" "; // 0 1 2 3 4
}
cout<<endl;
vector<int>::iterator it2 =vec.begin();
for( ; it2!=vec.end();++it2)
{
*it2=5;//使用 * 访问迭代器所指向的元素
cout<<*it2<<" "; // 5 5 5 5 5
}
cout<<endl;
//迭代器的运算
const vector<int>::iterator newiter=vec.begin();
vector<int>::iterator newiter2=vec.end();
cout<<newiter2-newiter<<endl;// 5
//调用模板函数
print(vec);
return 0;
}
迭代器的差值:
std::distance(start_id,end_it);//表示了元素个数
随机迭代器适用:直接相减,其他类型别的迭代器就需要逐个计数
4、迭代器失效问题
- 对于顺序容器vector,deque来讲,在进行删除erase()操作后,后边的每个元素的迭代器都会失效,后边的每个元素都会往前移动,erase()返回下一个有效的迭代器。
- 对于关联容器map,set来讲,进行删除erase()后,当前元素的迭代器失效,但因为其底层结构是红黑树,删除当前元素,并不会影响下一元素的迭代器,所以在调用erase()前,记录一下下一元素的迭代器即可。
- 对于list,它使用了不连续的内存分配,并且其erase()也返回下一个有效的迭代器,因此,上面两种方式都可以。
5、迭代器的萃取
首先,先看看STL的迭代器的源码是怎么写的:
typedef int ptrdiffer_t;//差值类型
struct intput_iterator_tag{}; //只读迭代器
struct output_interator_tag{}; //可写迭代器
struct forward_iterator_tag{}; //正向迭代器
struct bidirection_iterator_tag{}; //随机迭代器
template<class _C, class _Ty, class _D = ptrdiff_t, class _Pointer = _Ty*,class _Reference = _Ty&>
struct iterator
{
typedef _C iterator_category;//迭代器的类型
typedef _Ty value_type; //迭代器所迭代的数据的类型
typedef _D difference_type;//差值
typedef _Pointer pointer;//指针
typedef _Reference reference;//引用类型
};
//类型萃取器
template<class _Iterator>
struct iterator_traits
{
iterator_traits() {}
typedef typename _Iterator::iterator_category iterator_category;
typedef typename _Iterator::value_type value_type;
typedef typename _Iterator::difference_type differce_type;
typedef typename _Iterator::pointer pointer;
typedef typename _Iterator::reference reference;
};
template<class T>
struct iterator_traits<T*>
{
iterator_traits() {}
typedef typename random_access_iterator_tag iterator_category;
typedef typename T value_type;
typedef typename int differce_type;
typedef typename T * pointer;
typedef typename T& reference;
};
template<class T>
struct iterator_traits<const T*>
{
iterator_traits() {}
typedef typename random_access_iterator_tag iterator_category;
typedef typename T value_type;
typedef typename int differce_type;
typedef typename const T* pointer;
typedef typename const T& reference;
};
/// SGI
template<class _II>
inline typename iterator_traits<_II>::iterator_category
iterator_category(const _II&)
{
typedef typename iterator_traits<_II>::iterator_category cate;
return cate();
}
template<class _II>
inline typename iterator_traits<_II>::value_type *
value_type(const _II&)
{
return static_cast<typename iterator_traits<_II>::value_type*>(0);
}
template<class _II>
inline typename iterator_traits<_II>::difference_type*
difference_type(const _II&)
{
return static_cast<typename iterator_traits<_II>::difference_type*> (0);
}
// 正向迭代器
template<class _Ty, class _D = ptrdiff_t>
struct _Forit :public iterator<forward_iterator_tag, _Ty, _D> {};
// 双向迭代器
template<class _Ty,class _D = ptrdiff_t>
struct _Bidit :public iterator<bidirectional_iterator_tag,_Ty,_D>{};
// 随机迭代器
template<class _Ty,class _D = ptrdiff_t>
struct _Ranit :public iterator< random_access_iterator_tag, _Ty, _D> {};
template<class _II,class _D>
inline void __advance(_II& i, _D n, input_iterator_tag)
{
while (n--) ++i;
}
template<class _BI, class _D>
inline void __advance(_BI & i, _D n, bidirectional_iterator_tag)
{
if (n >= 0)
{
while (n--) ++i;
}
else
{
while (n++) --i;
}
}
template<class _RAI, class _D>
inline void __advance(_RAI& i, _D n, random_access_iterator_tag)
{
i += n;
}
template<class _II,class _D>
inline void advance(_II& i, _D n)
{
//iterator_traits<_II>();
//typedef typename iterator_traits<_II>::iterator_category cate;
__advance(i, n, iterator_category(i));
}
template<class _II>
inline typename iterator_traits<_II>::difference_type
__distance(_II _F, _II _L, input_iterator_tag)
{
typename iterator_traits<_II>::difference_type n = 0;
while (_F != _L)
{
_F++;
n++;
}
return n;
}
template<class _RAI>
inline typename iterator_traits<_RAI>::difference_type
__distance(_RAI _F, _RAI _L, random_access_iterator_tag)
{
return _L - _F;
}
template<class _II>
inline typename iterator_traits<_II>::difference_type
distance(_II _F, _II _L)
{
return __disstance(_F, _L, iterator_category(_F));
}
现在,来理解一下,迭代器是如何萃取到容器类型:
其实,从这里我们可以知道,迭代器的类型萃取是在编译时期就可以确定迭代器的类型了的。
之前我们还提到过,构造函数和析构函数的是否有关紧要,极大地影响了对象的创建与析构的代码的运行效率,所以用到类型萃取之后,编译器就会自动找到对应的函数来执行,以提高效率。
下一节:空间配置器...