C++中迭代器原理、失效和简单实现
目录
- 迭代器的使用
- 迭代器的种类
- 迭代器的失效
- 迭代器的实现
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++中迭代器原理、失效和简单实现的更多相关文章
- C++ STL迭代器原理和简单实现
1. 迭代器简介 为了提高C++编程的效率,STL(Standard Template Library)中提供了许多容器,包括vector.list.map.set等.然而有些容器(vector)可以 ...
- C++ STL中迭代器失效的问题
my_container.erase(iter); 其中my_container是STL的某种容器,iter是指向这个容器中某个元素的迭代器.如果不是在for,while循环中,这种方式删除元素没有问 ...
- 你的MySQL服务器开启SSL了吗?SSL在https和MySQL中的原理思考
最近,准备升级一组MySQL到5.7版本,在安装完MySQL5.7后,在其data目录下发现多了很多.pem类型的文件,然后通过查阅相关资料,才知这些文件是MySQL5.7使用SSL加密连接的.本篇主 ...
- tomcat原理分析与简单实现
tomcat原理分析与简单实现 https://blog.csdn.net/u014795347/article/details/52328221 2016年08月26日 14:48:18 卫卫羊习习 ...
- shiro中部分SpringCache失效问题
原文:https://www.cnblogs.com/liruiloveparents/p/9392159.html shiro中部分SpringCache失效问题 1.问题抛出 今天在做Spri ...
- 有关ViewPager的使用及解决Android下ViewPager和PagerAdapter中调用notifyDataSetChanged失效的问题
ViewPager是android-support-v4.jar包中的一个系统控件,继承自ViewGroup,专门用以实现左右滑动切换View的效果,使用时需要首先在Project->prope ...
- 在JavaScript中闭包的作用和简单的用法
在JavaScript中闭包的作用和简单的用法 一.闭包的简介 作用域链:在js中只有函数有作用域的概念,由于函数内能访问函数外部的数据,而函数外部不能访问函数内部的数据,由上述形成一种作用域访问的链 ...
- Shiro框架 (原理分析与简单实现)
Shiro框架(原理分析与简单实现) 有兴趣的同学也可以阅读我之前分享的:Java权限管理(授权与认证)CRM权限管理 (PS : 这篇博客里面的实现方式没有使用框架,完全是手写的授权与认证,可以 ...
- 分布式数据库中CAP原理(CAP+BASE)
分布式数据库中CAP原理(CAP+BASE) 传统的ACID 1)原子性(Atomicity): 事务里的所有操作要么全部做完,要么都不做,事务成功的条件是事务里的所有操作都成功. 2)一致性(Con ...
随机推荐
- NC入门笔记
简介: NC(全名NetCat),在网络界有"瑞士军刀"的美誉.它小巧而强悍,被设计成一个稳定的后门工具,能够直接由其它程序和脚本轻松驱动.同时,它也是一个功能强大的网络调试和探测 ...
- ModuleNotFoundError: No module named 'sqlite'
解决 ModuleNotFoundError: No module named 'sqlite'.问题 今天在将Python2.7升级至Python3.6后导入sqlite模块时出现了一下报错,到网上 ...
- [ACM_模拟] HDU 1006 Tick and Tick [时钟间隔角度问题]
Problem Description The three hands of the clock are rotating every second and meeting each other ma ...
- 1.WebApi介绍
1.WebApi是什么: WebAPI 是一种用来开发系统间接口.设备接口 API 的技术,基于 Http 协议,请求和返 回格式结果默认是 json 格式.比 WCF 更简单.更通用,比 WebSe ...
- WebService 工作原理及实例教程
一.WebService到底是什么? 先来看下标准的定义:Web Service也叫XML Web Service WebService是一种可以接收从Internet或者Intranet上的其它系统 ...
- .Net Core 自定义配置源从配置中心读取配置
配置,几乎所有的应用程序都离不开它..Net Framework时代我们使用App.config.Web.config,到了.Net Core的时代我们使用appsettings.json,这些我们再 ...
- MVVM Light 新手入门(2) :ViewModel / Model 中定义“属性” ,并在View中调用
今天学习MVVM架构中“属性”的添加并调用,特记录如下,学习资料均来自于网络,特别感谢翁智华的利刃 MVVMLight系列. 一个窗口的基本模型如下: View(视图) -> ViewModel ...
- 《ASP.NET MVC 5 破境之道》:概述
第一节:写作本书的目的 关于笔者 张晓亭(Mike Cheers),1982年出生,内蒙古辽阔的大草原是我的故乡. 没有高学历,没有侃侃而谈的高谈阔论,拥有的就是那一份对技术的执著,对自我价值的追求. ...
- AI贪吃蛇前瞻——基于Dijkstra算法的最短路径问题
在贪吃蛇流程结构优化之后,我又不满足于亲自操刀控制这条蠢蠢的蛇,干脆就让它升级成AI,我来看程序自己玩,哈哈. 一.Dijkstra算法原理 作为一种广为人知的单源最短路径算法,Dijkstra用于求 ...
- ovs-vsctl 命令详解
Open vSwitch中有多个命令,分别有不同的作用,大致如下: ovs-vsctl用于控制ovs db ovs-ofctl用于管理OpenFlow switch 的 flow ovs-dpctl用 ...