目录

  1. 迭代器的使用
  2. 迭代器的种类
  3. 迭代器的失效
  4. 迭代器的实现

1.迭代器的使用

为了提高C++编程的效率,STL中提供了许多容器,包括vector、list、map、set等。有些容器例如vector可以通过脚标索引的方式访问容器里面的数据,但是大部分的容器不能使用这种方式,例如list、map、set。STL中每种容器在实现的时候设计了一个内嵌的iterator类,不同的容器有自己专属的迭代器,使用迭代器来访问容器中的数据。除此之外,通过迭代器,可以将容器和通用算法结合在一起,只要给予算法不同的迭代器,就可以对不同容器执行相同的操作,例如find查找函数。迭代器对指针的一些基本操作如*、->、++、==、!=、=进行了重载,使其具有了遍历复杂数据结构的能力,其遍历机制取决于所遍历的数据结构,所有迭代的使用和指针的使用非常相似。通过begin,end函数获取容器的头部和尾部迭代器,end 迭代器不包含在容器之内,当begin和end返回的迭代器相同时表示容器为空。

template<typename InputIterator, typename T>
InputIterator find(InputIterator first, InputIterator last, const T &value)
{
while (first != last && *frist != value)
++first;
return first;
}
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
using namespace std; int main(int argc, const char *argv[])
{
int arr[] = { , , , , }; vector<int> iVec(arr, arr + );//定义容器vector
list<int> iList(arr, arr + );//定义容器list //在容器iVec的头部和尾部之间寻找整形数3
vector<int>::iterator iter1 = find(iVec.begin(), iVec.end(), );
if (iter1 == iVec.end())
cout<<"3 not found"<<endl;
else
cout<<"3 found"<<endl; //在容器iList的头部和尾部之间寻找整形数4
list<int>::iterator iter2 = find(iList.begin(), iList.end(), );
if (iter2 == iList.end())
cout<<"4 not found"<<endl;
else
cout<<"4 found"<<endl; return ;
}

2.迭代器的种类

根据迭代器所支持的操作,可以把迭代器分为5类。

1)   输入迭代器:是只读迭代器,在每个被遍历的位置上只能读取一次。例如上面find函数参数就是输入迭代器。

2)   输出迭代器:是只写迭代器,在每个被遍历的位置上只能被写一次。

3)   前向迭代器:兼具输入和输出迭代器的能力,但是它可以对同一个位置重复进行读和写。但它不支持operator--,所以只能向前移动。

4)   双向迭代器:很像前向迭代器,只是它向后移动和向前移动同样容易。

5)   随机访问迭代器:有双向迭代器的所有功能。而且,它还提供了“迭代器算术”,即在一步内可以向前或向后跳跃任意位置,  包含指针的所有操作,可进行随机访问,随意移动指定的步数。支持前面四种Iterator的所有操作,并另外支持it + n、it - n、it += n、 it -= n、it1 - it2和it[n]等操作。

STL每种容器类型都定义了 const_iterator,只能读取容器的值,不能修改所指向容器范围内元素的值。vector、string、Deque随机存取迭代器;List、Set、map、mutiset、multimap双向迭代器。

3.迭代器失效

容器的插入insert和erase操作可能导致迭代器失效,对于erase操作不要使用操作之前的迭代器,因为erase的那个迭代器一定失效了,正确的做法是返回删除操作时候的那个迭代器。

#include <vector>
using namespace std; int main(int argc, const char *argv[]) {
int arr[] = { , , , , }; vector<int> iVec(arr, arr + ); //定义容器vector
//迭代器失效
// for (vector<int>::iterator it = iVec.begin(); it != iVec.end();) {
// iVec.erase(it);
// }
//返回erase操作之后的迭代器
for (vector<int>::iterator it = iVec.begin();it != iVec.end();) {
it = iVec.erase(it);
}
return ;
}

4.迭代器的实现

STL中每个容器都有自己的迭代器,各种迭代器的接口相同,内部实现却不相同,这也直接体现了泛型编程的概念,下面在单链表类中内嵌入一个iterator的类来实现单链表的迭代

 #include <iostream>

 template<typename T>
struct ListNode {
T value;
ListNode* next;
ListNode() {
next = ;
}
ListNode(T val, ListNode *p = nullptr) :
value(val), next(p) {
}
}; template<typename T>
class List {
private:
ListNode<T> *m_pHead;
ListNode<T> *m_pTail;
int m_nSize;
public:
List() {
m_pHead = nullptr;
m_pTail = nullptr;
m_nSize = ;
}
//从链表尾部插入元素
void push_back(T value) {
if (m_pHead == nullptr) {
m_pHead = new ListNode<T>(value);
m_pTail = m_pHead;
} else {
m_pTail->next = new ListNode<T>(value);
m_pTail = m_pTail->next;
} } //打印链表元素
void print(std::ostream &os = std::cout) const {
for (ListNode<T> *ptr = m_pHead; ptr != m_pTail->next ; ptr = ptr->next)
std::cout << ptr->value << " ";
os << std::endl;
} //内置迭代器
class iterator {
private:
ListNode<T> *m_ptr;
public:
iterator(ListNode<T>* p = nullptr) :
m_ptr(p) {
} T operator*() const {
return m_ptr->value;
}
ListNode<T>* operator->() const {
return m_ptr;
}
iterator& operator++() {
m_ptr = m_ptr->next;
return *this;
}
iterator operator++(int) {
ListNode<T>* tmp = m_ptr;
m_ptr = m_ptr->next;
return iterator(tmp);
} bool operator==(const iterator &arg) const {
return arg.m_ptr == this->m_ptr;
} bool operator!=(const iterator &arg) const {
return arg.m_ptr != this->m_ptr;
} }; //返回链表头部指针
iterator begin() const {
return iterator(m_pHead);
} //返回链表尾部指针
iterator end() const {
return iterator(m_pTail->next);
} //其它成员函数 }; int main() {
List<int> l;
l.push_back();
l.push_back();
l.print();
for (List<int>::iterator it = l.begin(); it != l.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return ;
}

参考: http://blog.csdn.net/shudou/article/details/11099931

C++中迭代器原理、失效和简单实现的更多相关文章

  1. C++ STL迭代器原理和简单实现

    1. 迭代器简介 为了提高C++编程的效率,STL(Standard Template Library)中提供了许多容器,包括vector.list.map.set等.然而有些容器(vector)可以 ...

  2. C++ STL中迭代器失效的问题

    my_container.erase(iter); 其中my_container是STL的某种容器,iter是指向这个容器中某个元素的迭代器.如果不是在for,while循环中,这种方式删除元素没有问 ...

  3. 你的MySQL服务器开启SSL了吗?SSL在https和MySQL中的原理思考

    最近,准备升级一组MySQL到5.7版本,在安装完MySQL5.7后,在其data目录下发现多了很多.pem类型的文件,然后通过查阅相关资料,才知这些文件是MySQL5.7使用SSL加密连接的.本篇主 ...

  4. tomcat原理分析与简单实现

    tomcat原理分析与简单实现 https://blog.csdn.net/u014795347/article/details/52328221 2016年08月26日 14:48:18 卫卫羊习习 ...

  5. shiro中部分SpringCache失效问题

    原文:https://www.cnblogs.com/liruiloveparents/p/9392159.html shiro中部分SpringCache失效问题   1.问题抛出 今天在做Spri ...

  6. 有关ViewPager的使用及解决Android下ViewPager和PagerAdapter中调用notifyDataSetChanged失效的问题

    ViewPager是android-support-v4.jar包中的一个系统控件,继承自ViewGroup,专门用以实现左右滑动切换View的效果,使用时需要首先在Project->prope ...

  7. 在JavaScript中闭包的作用和简单的用法

    在JavaScript中闭包的作用和简单的用法 一.闭包的简介 作用域链:在js中只有函数有作用域的概念,由于函数内能访问函数外部的数据,而函数外部不能访问函数内部的数据,由上述形成一种作用域访问的链 ...

  8. Shiro框架 (原理分析与简单实现)

    Shiro框架(原理分析与简单实现) 有兴趣的同学也可以阅读我之前分享的:Java权限管理(授权与认证)CRM权限管理   (PS : 这篇博客里面的实现方式没有使用框架,完全是手写的授权与认证,可以 ...

  9. 分布式数据库中CAP原理(CAP+BASE)

    分布式数据库中CAP原理(CAP+BASE) 传统的ACID 1)原子性(Atomicity): 事务里的所有操作要么全部做完,要么都不做,事务成功的条件是事务里的所有操作都成功. 2)一致性(Con ...

随机推荐

  1. springMVC 开涛 数据绑定

    纸上得来终觉浅,绝知此事要躬行. 一.@requestParam //使用方法URL:?username="sfp" test(@RequestParam(value=" ...

  2. lua的table的删除操作

    直接使用table的remove方法 , , } table.remove(tab) --默认删除最后一个元素,第二个参数可以指定删除位置 删除后,后面的元素会往前移动.有点像C++的std::vec ...

  3. leetcode-爬楼梯(动态规划)

    假设你正在爬楼梯.需要 n 阶你才能到达楼顶. 每次你可以爬 1 或 2 个台阶.你有多少种不同的方法可以爬到楼顶呢? 注意:给定 n 是一个正整数. 示例 1: 输入: 2 输出: 2 解释: 有两 ...

  4. 自适应XAML布局经验总结 (四)区域布局设计模式

    本系列对实际项目中的XAML布局场景进行总结,给出了较优化的自适应布局解决方案,希望对大家有所帮助. 下面介绍区域布局设计模式. 7. 头尾模式 页面有时分为顶部栏,中间内容和底部栏三部分.这时可以使 ...

  5. Checkpoint--查看各DB上的脏页

    可以使用sys.dm_os_buffer_descriptors来看数据页在buffer pool中的状态,其中is_modified来标示数据页是否为脏页 --------------------- ...

  6. 射线与平面的相交检测(Ray-Plane intersection test)【转】

    射线的定义 在欧几里德几何中,射线的定义是:直线上一点和它一旁的部分.由此可知,射线有两个性质,一是只有一个端点,二是一端无限延伸. 射线的参数方程 其中p0是射线的起点, u是射线的方向向量,t & ...

  7. 使用FluentScheduler实现定时任务管理

    之前定时任务一直用的Windows服务,前段时间发现FluentScheduler这个框架,他跟Quarz.Net,Hangfire一样都是任务调度框架,但是相对使用而言我觉得FluentSchedu ...

  8. 基于Spring MVC的web应用随应用启动而加载

    写个类实现org.springframework.context.ApplicationContextAware接口即可. 但是如下的程序会在启动时加载两次: @Controller public c ...

  9. POST与GET请求的区别

    https://www.cnblogs.com/logsharing/p/8448446.html 返回主页 在途中# 博客园首页新随笔联系订阅管理 随笔 - 33 文章 - 5 评论 - 40 GE ...

  10. nginx 场景业务汇总 (中)

    本文链接:http://www.cnblogs.com/zhenghongxin/p/8906225.html,如果可以,请阅读上篇 <nginx场景业务汇总(初)> (十三)负载均衡 轮 ...