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 ...
随机推荐
- Oracle财务系统常用标准报表
http://erpoperator.blog.163.com/blog/static/17899637220111181121616/ Oracle财务系统常用标准报表 总账系统 系统报表名 中文译 ...
- C++虚函数表(vtbl)
C++的虚函数的作用就是为了实现多态的机制,利用内存的指针偏移来实现将基类型的指针指向的内存空间用子类对象来初始化.这样经过内部虚表的运作,实现可以通过基类指针来调用子类所定义的方法. 这种技术,其实 ...
- SSH 安全建议
当你查看你的 SSH 服务日志,可能你会发现充斥着一些不怀好意的尝试性登录.这里有 5 条常规建议(和一些个别特殊策略)可以让你的 OpenSSH 会话更加安全. 强化密码登录 密码登录很方便,因为你 ...
- [ACM_动态规划] hdu1003 Max Sum [最大连续子串和]
Problem Description Given a sequence a[1],a[2],a[3]......a[n], your job is to calculate the max sum ...
- DAC--解决windows验证无法登陆的问题
解决思路: 使用单用户管理员模式启动SQL Server,再使用SQLCMD连接上数据库,此时有sysadmin权限,添加用户并赋予相应权限 1>停止SQL Server服务运行 2>在C ...
- python实现斐波那契数列笔记
斐波那契数列即著名的兔子数列:1.1.2.3.5.8.13.21.34.…… 数列特点:该数列从第三项开始,每个数的值为其前两个数之和,用python实现起来很简单: a=0 b=1 while b ...
- npm安装和Vue运行
一.开始: 下载地址:http://nodejs.cn/download/ 下载安装: 直到 二.打开CMD,检查是否正常 在安装目录里新增两个文件夹 然后运行命令:如下图: npm config s ...
- uwp ListView列表滑动特效
在看过一篇文章 WPF自定义控件之列表滑动特效 PowerListBox http://www.cnblogs.com/ShenNan/p/4993374.html#3619585 实现了滑动的特效 ...
- S11 day 94 RestFramework 之 APIView视图
VIEW视图(Django自带的) 1. url url(r'login/$', views.login.as_view()), 2.点开 as_view() , as_view()为类方法. l ...
- 在linux下搭建python+django环境
下载python3,进行编译安装,运行django程序 在 /opt目录中安装 cd /opt 1.解决python编译安装所需的软件依赖 yum install gcc patch libffi-d ...