STL迭代器和指针

要访问顺序容器和关联容器中的元素,需要通过“迭代器(iterator)”进行。迭代器是一个变量,相当于容器和操纵容器的算法之间的中介。迭代器可以指向容器中的某个元素,通过迭代器就可以读写它指向的元素。从这一点上看,迭代器和指针类似。


迭代器按照定义方式分成以下四种
1) 正向迭代器,定义方法如下:容器类名::iterator  迭代器名;
2) 常量正向迭代器,定义方法如下:容器类名::const_iterator  迭代器名;
3) 反向迭代器,定义方法如下:容器类名::reverse_iterator  迭代器名;
4) 常量反向迭代器,定义方法如下:容器类名::const_reverse_iterator  迭代器名;

通过迭代器可以读取它指向的元素,*迭代器名就表示迭代器指向的元素。通过非常量迭代器还能修改其指向的元素。
迭代器都可以进行++操作。反向迭代器和正向迭代器的区别在于:

  • 对正向迭代器进行++操作时,迭代器会指向容器中的后一个元素;
  • 而对反向迭代器进行++操作时,迭代器会指向容器中的前一个元素。

下面的程序演示了如何通过迭代器遍历一个 vector 容器中的所有元素:

#include <iostream>
#include <vector>
using namespace std;
int main()
{
    vector<int> v;  //v是存放int类型变量的可变长数组,开始时没有元素
    for (int n = 0; n<5; ++n)
        v.push_back(n);  //push_back成员函数在vector容器尾部添加一个元素
    vector<int>::iterator i;  //定义正向迭代器
    for (i = v.begin(); i != v.end(); ++i) {  //用迭代器遍历容器
        cout << *i << " ";  //*i 就是迭代器i指向的元素
        *i *= 2;  //每个元素变为原来的2倍
    }
    cout << endl;
    //用反向迭代器遍历容器
    for (vector<int>::reverse_iterator j = v.rbegin(); j != v.rend(); ++j)
        cout << *j << " ";
    return 0;
}

程序的输出结果是:
0 1 2 3 4
8 6 4 2 0
第 10 行和第 16 行,++i++j相比于写i++j++,程序的执行速度更快。回顾++被重载成前置和后置运算符的例子如下:

CDemo CDemo::operator++ ()
{  //前置++
    ++n;
    return *this;
}
CDemo CDemo::operator ++(int k)
{  //后置++
    CDemo tmp(*this);  //记录修改前的对象
    n++;
    return tmp;  //返回修改前的对象
}

后置++要多生成一个局部对象 tmp,因此执行速度比前置的慢。同理,迭代器是一个对象,STL 在重载迭代器的++运算符时,后置形式也比前置形式慢。在次数很多的循环中,++ii++可能就会造成运行时间上可观的差别了。对循环控制变量i,要养成写++i、不写i++的习惯。

注意,容器适配器 stack、queue 和 priority_queue 没有迭代器。容器适配器有一些成员函数,可以用来对元素进行访问。

迭代器的辅助函数

STL 中有用于操作迭代器的三个函数模板,它们是:

  • advance(p, n):使迭代器 p 向前或向后移动 n 个元素。
  • distance(p, q):计算两个迭代器之间的距离,即迭代器 p 经过多少次 + + 操作后和迭代器 q 相等。如果调用时 p 已经指向 q 的后面,则这个函数会陷入死循环。
  • iter_swap(p, q):用于交换两个迭代器 p、q 指向的值。

如果只讨论 STL container 类的 iterator,它们其实都是一种泛型指针。C风格指针是属于 iterator 的一种的。iterator 根据功能做了更细的划分,STL 中的 iterator 分成了五类。
我觉得它们的区别:
在范围上,pointer 属于 iterator 的一种(random access iterator)
在功能上,iterator 有着比 pointer 更细的划分并对应能力不同的功能(重载不同的运算符)
在行为上,iterator 比 pointer 更统一和良好的用法(更轻易使用 begin()、end()且不用担心越界)

迭代器:
      (1)迭代器不是指针,是类模板,表现的像指针。
他只是模拟了指针的一些功能,通过重载了指针的一些操作符,->,*,++ --等封装了指针,是一个“可遍历STL( Standard Template Library)容器内全部或部分元素”的对象, 本质是封装了原生指针,是指针概念的一种提升(lift),提供了比指针更高级的行为,相当于一种智能指针,他可以根据不同类型的数据结构来实现不同的++,--等操作;
      (2)迭代器返回的是对象引用而不是对象的值,所以cout只能输出迭代器使用*取值后的值而不能直接输出其自身。
      (3)在设计模式中有一种模式叫迭代器模式,简单来说就是提供一种方法,在不需要暴露某个容器的内部表现形式情况下,使之能依次访问该容器中的各个元素,这种设计思维在STL中得到了广泛的应用,是STL的关键所在,通过迭代器,容器和算法可以有机的粘合在一起,只要对算法给予不同的迭代器,就可以对不同容器进行相同的操作。
  注:迭代器在使用后就释放了,不能再继续使用,但是指针可以!!
指针:
        指针能指向函数而迭代器不行,迭代器只能指向容器;指针是迭代器的一种。
指针只能用于某些特定的容器;迭代器是指针的抽象和泛化。所以,指针满足迭代器的一切要求。
        总之,指针和迭代器是有很大差别的,虽然他们表现的行为相似,但是本质是不一样的!一个是类模板,一个是存放一个家伙的地址的指针变量。

在《C++编程剖析》一书中,对类似于 void f(T*) 一类的函数,如果传给其一个迭代器,不一定会奏效,解决方案就是使用&*iterator,即,不管使用的是迭代器还是指针,都对其先解引在取地址,但是有一个条件,事先并没有病态的去重载 operator&(),使其返回其他的值。。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STL(标准模板库)是一种用于访问容元素的对象,它提供了一种统一的方式来遍历和操作容中的元素。STL中的是用模板类实现的,它们被设计为与容独立并提供统一的接口。 的实现需要满足以下要求: 1. 提供指向容元素的指针操作符(*),使得可以通过访问元素。 2. 提供用于移动到容下一个或上一个元素的算术操作符(++、--),使得可以在容中移动。 3. 提供比较操作符(==、!=、<、>等),用于比较两个的位置关系。 具体实现上,STL可以分为以下几种类型: 1. 输入(Input Iterator):仅能从容中读取元素,只支持单向移动。 2. 输出(Output Iterator):仅能向容中写入元素,只支持单向移动。 3. 前向(Forward Iterator):支持从容中读取和写入元素,支持单向移动。 4. 双向(Bidirectional Iterator):支持从容中读取和写入元素,支持双向移动。 5. 随机访问(Random Access Iterator):支持从容中读取和写入元素,支持任意方向的移动,并且可以进行随机访问。 在STL中,不同类型的容提供了不同级别的支持。例如,vector和deque提供了随机访问,而list只提供了双向的实现是通过重载操作符和模板机制来实现的,以满足不同类型容的特定需求。 总结起来,STL是一种通用的访问容元素的对象,其实现通过模板类和操作符重载来实现不同级别的功能支持。这种设计使得STL的算法可以独立于具体容而操作,提供了高度的灵活性和可扩展性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值