C++ 迭代器原理、失效和实现

目录

  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[5] = { 1, 2, 3, 4, 5};

    vector<int> iVec(arr, arr + 5);//定义容器vector
    list<int> iList(arr, arr + 5);//定义容器list

    //在容器iVec的头部和尾部之间寻找整形数3
    vector<int>::iterator iter1 = find(iVec.begin(), iVec.end(), 3);
    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(), 4);
    if (iter2 == iList.end())
        cout<<"4 not found"<<endl;
    else
        cout<<"4 found"<<endl;

    return 0;
}

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[5] = { 1, 2, 3, 4, 5 };

    vector<int> iVec(arr, arr + 5); //定义容器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 0;
}

4.迭代器的实现

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

  1 #include <iostream>
  2
  3 template<typename T>
  4 struct ListNode {
  5     T value;
  6     ListNode* next;
  7     ListNode() {
  8         next = 0;
  9     }
 10     ListNode(T val, ListNode *p = nullptr) :
 11             value(val), next(p) {
 12     }
 13 };
 14
 15 template<typename T>
 16 class List {
 17 private:
 18     ListNode<T> *m_pHead;
 19     ListNode<T> *m_pTail;
 20     int m_nSize;
 21 public:
 22     List() {
 23         m_pHead = nullptr;
 24         m_pTail = nullptr;
 25         m_nSize = 0;
 26     }
 27     //从链表尾部插入元素
 28     void push_back(T value) {
 29         if (m_pHead == nullptr) {
 30             m_pHead = new ListNode<T>(value);
 31             m_pTail = m_pHead;
 32         } else {
 33             m_pTail->next = new ListNode<T>(value);
 34             m_pTail = m_pTail->next;
 35         }
 36
 37     }
 38
 39     //打印链表元素
 40     void print(std::ostream &os = std::cout) const {
 41         for (ListNode<T> *ptr = m_pHead; ptr != m_pTail->next ; ptr = ptr->next)
 42             std::cout << ptr->value << " ";
 43         os << std::endl;
 44     }
 45
 46     //内置迭代器
 47     class iterator {
 48     private:
 49         ListNode<T> *m_ptr;
 50     public:
 51         iterator(ListNode<T>* p = nullptr) :
 52                 m_ptr(p) {
 53         }
 54
 55         T operator*() const {
 56             return m_ptr->value;
 57         }
 58         ListNode<T>* operator->() const {
 59             return m_ptr;
 60         }
 61         iterator& operator++() {
 62             m_ptr = m_ptr->next;
 63             return *this;
 64         }
 65         iterator operator++(int) {
 66             ListNode<T>* tmp = m_ptr;
 67             m_ptr = m_ptr->next;
 68             return iterator(tmp);
 69         }
 70
 71         bool operator==(const iterator &arg) const {
 72             return arg.m_ptr == this->m_ptr;
 73         }
 74
 75         bool operator!=(const iterator &arg) const {
 76             return arg.m_ptr != this->m_ptr;
 77         }
 78
 79     };
 80
 81     //返回链表头部指针
 82     iterator begin() const {
 83         return iterator(m_pHead);
 84     }
 85
 86     //返回链表尾部指针
 87     iterator end() const {
 88         return iterator(m_pTail->next);
 89     }
 90
 91     //其它成员函数
 92
 93 };
 94
 95 int main() {
 96     List<int> l;
 97     l.push_back(1);
 98     l.push_back(2);
 99     l.print();
100     for (List<int>::iterator it = l.begin(); it != l.end(); ++it) {
101         std::cout << *it << " ";
102     }
103     std::cout << std::endl;
104     return 0;
105 }

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

时间: 2024-11-08 12:58:33

C++ 迭代器原理、失效和实现的相关文章

关于__setitem__,__getitem__,delitem__以及__slots__,迭代器原理,上下文管理协议还有元类

关于__setitem__,__getitem__,delitem__ 类似于以前的学过的__setattr__,__getattr__... 不同之处在于item结尾的是用于对象以字典添加的形势添加,查看和删除属性的时候才会触发,如下例子: class Foo(object): # __slots__=['x','y'] def __setitem__(self, key, value): print('我在写入') self.__dict__[key]=value def __getitem

java 迭代器原理初探

今天学习了迭代器,老师对迭代器的两个方法hasNext()和Next(),做了深入的理解,并且举了一个简单的例子大致模拟了底层的实现,下面我来记录下实现的过程,首先建立了一个 Collection.java 这是模拟的Collection接口 代码如下: package cn.itcast.studyIterator; public interface Collection {    public Object get(int index);    public int size();    p

迭代器原理和使用

一.迭代器 1.说明: 迭代器是访问集合元素的一种方式.迭代器的对象从集合的第一个元素开始访问,直到所有的元素被访问结束.迭代器只能往前不会退后. 不过也没什么,因为人们很少在迭代过程中往后退.另外迭代器一大优点是不要求事先准备好整个迭代过程中的所有元素.迭代器仅仅在迭代 到某个元素时才计算该元素,而在这之前或者之后,元素可以不存在或者被销毁.这个特点使得它特别适合用于遍历一些巨大的或者无限的集合 ,比如几个G的文件. 2.特点: ①访问者不需要关心迭代器内部结构,仅需要通过__next__()

vector迭代器失效的几种情况

在泛型编程还是STL的实际运用中,迭代器(iterator)无疑扮演者重要的角色.迭代器是一种类似于指针的对象(如可以内容提领,成员访问等),但他又不仅仅是一种普通的指针.关于迭代器失效,我们可以看下面这个例子: #include<vector>#include<list>void PrintVector(const vector<int>& v){    vector<int>::const_iterator it = v.begin();    

vector迭代器失效的一种情形

使用过STL的人都应该知道关于迭代器失效的原理,这里以后vector迭代器失效为例: 第一种:当插入一个元素到vector中,如果插入后容器已满,那么容器将新开辟一块内存区域,然后 将原内存中的数据拷贝到新的内存区域,同时释放旧的内存.这样之前指向旧内存的迭代器就会指向 不确定内存,这块内存要么释放,要么释放后又用作其他用途.这便导致了迭代器失效. 第二种:当删除容器中一个元素后,该迭代器所指向的元素已经被删除,那么也造成迭代器失效. 这里我们主要讨论下第二种情况. 我们先举个例子说明: 比如v

STL源码分析--迭代器总结、迭代器失效总结

Vector 1.内部数据结构:连续存储,例如数组. 2.随机访问每个元素,所需要的时间为常量. 3.在末尾增加或删除元素所需时间与元素数目无关,在中间或开头增加或删除元素所需时间随元素数目呈线性变化. 4.可动态增加或减少元素,内存管理自动完成,但程序员可以使用reserve()成员函数来管理内存. 5.迭代器失效 插入:vector的迭代器在内存重新分配时将失效(它所指向的元素在该操作的前后不再相同).当把超过capacity()-size()个元素插入vector中时,内存会重新分配,所有

STL迭代器失效总结

转自: http://blog.csdn.net/hackbuteer1/article/details/7734382             http://m.blog.csdn.net/blog/xhu_eternalcc/38355619 迭代器(iterator)是一个可以对其执行类似指针的操作(如:解除引用(operator*())和递增(operator++()))的对象,我们可以将它理 解成为一个指针.但它又不是我们所谓普通的指针,我们可以称之为广义指针,你可以通过sizeof(

迭代器Iterator的底层实现原理

第一步:没有接口的迭代器简单实现原理 1 package com.bjsxt.xiaofei; 2 /** 3 * 迭代器底层原理 4 * 方法: 5 * hasNext() 6 * next() 7 * remove() 8 * @ClassName: MyAarryList 9 * @Description: TODO(这里用一句话描述这个类的作用) 10 * @author 尚晓飞 11 * @date 2014-7-29 下午7:06:09 12 * 13 */ 14 public cl

c++之迭代器失效

1.首先从一到题目开始谈说起迭代器失效.有时我们很自然并且自信地 用下面方法删除vector元素: #include <iostream>#include <stdio.h>#include <vector>#include <algorithm>#include <string> void del_elem(vector<string> &vec, const char * elem) { vector<string&