关闭

迭代器萃取和反向迭代器

标签: 迭代器萃取特性萃取机反向迭代器
461人阅读 评论(0) 收藏 举报
分类:

迭代器是什么

  • 迭代器是一种行为类似指针的对象,通过重载一些操作指针的如++,--,*,->,可以不知道容器的结构来访问容器。

为什么每一种容器都提供有专属的迭代器

要设计出一个容器的迭代器就必须对这个容器实现的细节非常的了解,既然无法避免曝光容器的细节,那么就把这个工作交给这个容器的设计者,这样一来,容器的所有细节得到了封装,不被使用者看到。

  • 第一为了保持数据结构的面向对象的封装性
  • 第二是为了让使用stl的成本降低。

迭代器的作用:

  • 1.可以不知道容器的结构来访问容器。
  • 2.向胶水一样的把算法完美的作用到容器上。

STL的核心思想:效率和复用

  • 算法:算法关注的是逻辑
  • 容器:数据管理

算法是通过迭代器作用到算法上的,所以为了算法的效率,于是就有了迭代器萃取,根据迭代器的内嵌类型,决定出迭代器类型,选出合适的算法。

问题: 算法中要定义一个变量, 以“迭代器指向对象的类型value type”为型别,该怎么定义这个变量?

  • function template的推演

算法中可以根据传入的迭代器参数,通过模板参数类型的推演出,推演出其迭代器所指对象的类型;但返回值无法推演。

  • 在迭代器里面设置内嵌value type 型别,在需要的地方通过 Iterator::value type来解决。

对于迭代器是class type可以设置内嵌类型value type来解决;但若例如vector的迭代器是T*,就无法设置迭代器的内嵌型别。

  • 偏特化(partial specialization)解决上面问题
template<class it>
struct iterator_traits{   //对内嵌多一层封装,用来萃取。
    typedef typename it::value_type value_type;
}
template<class T>
struct iterator_traits<T*>{  //偏特化版本——迭代器是一个原生指针
    typedef T value_type;
}
template<class T>
struct iterator_traits<const T*>{ //偏特化版本——对于“指向常数对象的指针”,要让它的value_type变成no-const,赋值不能赋值。
    typedef T value_type;
}

这里使用的是类型萃取的方法,通过上面的偏特化萃取出原生指针迭代器的value_type,这个iterator_traits不仅可以萃取value_type,通过这个“特性萃取机”可以过得相应的型别,特性就是迭代器相应的五种类型,若下所示;用上方的方法同样可以是对以下五种相别进行萃取,得出和迭代器匹配的类型。

  • 五个内嵌型别
tempalte<class It>
struct iterator_traits{
    typedef typename It::value_type value_type;
    typedef typename It::different_type different_type;
    typedef typename It::pointer pointer;
    typedef typename It::reference reference;
    typedef typename It::iterator_category iterator_category; //迭代器的种类,被分成5类
}
  • 迭代器的五种种类 

  • input iterator :只读,不允许被修改
  • output iterator :只写,形式上的一类,不存在只写的迭代器
  • Forward iterator :单向迭代器
  • Bidirectional iterator :双向迭代器
  • Random Access iterator :随机迭代器,支持所有指针的算术能力,如p++,p--,p[n]等。
struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};

这些类只做标记使用

  • 作用一:是使用这个标签左第三个参数促成算法重载,方便萃取。
  • 作用二:是通过这种继承关系可以消除“单纯只做传递功能而被调用”的函数,例如没有实现Forward_iterator,那么inputiterator版本的算法也可以通过继承切片的行为被Forward_iterator使用。

迭代器种类的萃取是为了算法的高效率

一直算法对于不同种类的迭代器实现的方式可能就不同,那么效率就自然不同,因此为了使每种迭代器使用同一个算法时,可以使用最适合自己的那个版本,就有了迭代器种类的萃取

  • 开始是通过选择语句,通过一个函数判断这个迭代器属于哪个种类,然后选择出对应算法的版本。
  • 为了提高效率,可以在编译时就确定选用哪个版本,因此就引入重载,通过特性萃取机萃取出迭代器类型属于哪一个。 重载:算法的第三个参数实参为iterator_traits<iterator>::iterator_category(),形参为五种种类的一种类型.

以上就是迭代器的萃取,可以通过下面代码实例加深理解: 



迭代器的保证

为了符合规范,任何迭代器必须定义五个内嵌型别,以便于traits萃取,否则将自别与STL架构,可能无法与STL的组件完美搭配。

反向迭代器

  • 通过正向迭代器适配出反向迭代器,在反向迭代器里顶一个正向迭代器对象,对这个对象进行反向操作,具体看下面代码。
  • 反向迭代器的REnd()是正向迭代器的Begin()
  • 反向迭代器的RBegin()是正向迭代器的End()。

解引用的时候返回正向顺序的下一个位置的值,也就是逆序的前一个值,可以达到上面的效果。

  • explicit 加到构造函数前面避免隐式类型装换,防止 把正向迭代器的Begin或end隐式的赋给反向迭代器
/***********************反向迭代器(适配器)***********************************/
template<class It>
struct ReverseIterator 
{
	It _it;  //某个正向迭代器
	typedef typename IteratorTraits<It>::IteratorCategory IteratorCategory;
	typedef typename IteratorTraits<It>::ValueType ValueType;
	typedef typename IteratorTraits<It>::DifferenceType DifferenceType;
	typedef typename IteratorTraits<It>::Pointer Pointer;
	typedef typename IteratorTraits<It>::Reference Reference;
	typedef ReverseIterator<It> Self;

	//explicit 避免隐式类型转换,例如把 ReIt = l.Begin(),这是不允许的。
	explicit ReverseIterator(It it)
		:_it(it)
	{}

 	Self& operator++()
	{
		--_it;
		return *this;
	}
	Self& operator++(int)
	{
		Self tmp = *this;
		--_it;
		return tmp;
	}
	Self& operator--()
	{
		++_it;
		return *this;
	}
	Self& operator--(int)
	{
		Self tmp = *this;
		++_it;
		return tmp;
	}
	Reference operator*()
	{
		//为了RBegin和REnd符合常规思维,随意这里解引用后一个位置,
		It tmp = _it;
		--tmp;
		return (*tmp);
	}
	Pointer operator->()
	{
		return &(*_it);
	}
	bool operator==(Self& it)
	{
		return _it == it._it ? true : false;
	}
	bool operator!=(Self& it)
	{
		return _it != it._it ? true : false;
	}

};
0
0
查看评论

读书笔记-STL迭代器之萃取技术

迭代器是一种抽象的设计概念,它提供一种方法,能够依序巡防某个容器的各个元素,而无需暴露该容器的内部数据的组织结构,将数据容器和算法(对容器内元素的操作)分开,彼此独立设计
  • caoyan_12727
  • caoyan_12727
  • 2016-09-03 20:14
  • 287

STL迭代器的"特性萃取机"-----Traits

Traits就像一台”特性萃取机“,它可以毫无偏差的榨取各个迭代器的特性。在讲Traits之前,我们先要把迭代器的特性搞清楚。 什么是迭代器的特性? 迭代器的特性就是迭代器的型别,最常用的迭代器的5中种型别(这5种型别都为内嵌型别),每一种迭代器都有以下五种型的定义: 1.value_ty...
  • LLZK_
  • LLZK_
  • 2016-12-17 21:49
  • 666

C++迭代器之'反向迭代器'

反向迭代器(Reverse Iterator)是普通迭代器的适配器,通过重新定义自增和自减操作,以达到按反序遍历元素的目的。如果在标准算法库中用反向迭代器来代替普通的迭代器,那么运行结果与正常情况下相反。除此之外,其用法与普通迭代器完全一样,我们不作详细讨论。    ...
  • BonChoix
  • BonChoix
  • 2012-10-11 20:00
  • 4528

【ThinkingInJava】23、反向迭代器

/** * 书本:《Thinking In Java》 * 功能:我们希望在默认的向前迭代器的基础上,添加产生反向迭代器的能力。 * 文件:AdapterMethodIdiom.java * 时间:2015年4月8日19:59:01 * 作者:cutter_point */ package Less...
  • cutter_point
  • cutter_point
  • 2015-05-03 20:27
  • 734

java集合之列表迭代器ListIterator

在操作集合时,常常使用数组和动态的ArrayList(数组列表,因为ArrayList的底层实现是通过数组来实现的)类,但是,数组和数组列表在操作的时候有一个重大缺陷,如:在数组中删除一个元素时,当元素被删除后将导致该元素后面的元素都要想数组的前端移动;在数组中插入一个元素时,将导致该元素相邻的元素...
  • Calvex880714
  • Calvex880714
  • 2014-11-08 09:09
  • 5001

反向迭代器reverse_iterator与正向迭代器iterator之间的转换(list反向删除元素的方法)

首先,本文的公众号地址为:你真的会清理std::list的元素吗? 刚开通公众号,请求大家关注一下,谢谢大家。公众号二维码如下:有经验的程序员都知道,list是链表,可以遍历删除,删除的过程类似于以下代码(遍历删除521):int key=521;//程序员就不要爱情了吧 list::iterato...
  • onlysingleboy
  • onlysingleboy
  • 2017-07-05 23:01
  • 611

STL 反向迭代器(rbegin,rend)

#include #include using namespace std; int main() { sets; s.insert(1); cout<<*s.rbegin(); return 0; } 直接输出最后一个元素 以下为转载的文章---------...
  • qq_24489717
  • qq_24489717
  • 2015-12-18 11:14
  • 1022

C++ vector反向迭代器的使用

反向迭代器 反向迭代器其实没什么特殊的,他只是在遍历的方向上和普通迭代器不通而已: 每一个容器里面都有Iterator(迭代器),可以从容器的begin位置到end-1位置,通过++来遍历。 同样也有个反向迭代器reverse_iterator,从rbegin(=end)到rend(=...
  • jiangqin115
  • jiangqin115
  • 2015-02-10 09:58
  • 1394

js迭代器之倒序访问迭代器及终止迭代器

迭代器模式的定义非常松散,所以我们可以有多种多样的迭代器实现。总的来说,迭代器模式提供了循环访问一个聚合对象中每个元素的方法,但他没有规定 我们一顺序、倒序还是中序来循环遍历聚合对象。 下面我们分分钟实现一个倒序访问的迭代器: var reveseEach ...
  • Hi_xiexialing
  • Hi_xiexialing
  • 2017-01-20 16:53
  • 311

vector 反向迭代器的使用

反向迭代器 1 反向迭代器其实没什么特殊的,他只是在遍历的方向上和普通迭代器不通而已:每一个容器里面都有Iterator(迭代器),可以从容器的begin位置到end-1位置,通过++来遍历。同样也有个反向迭代器reverse_iterator,从rbegin(=end)到...
  • skillart
  • skillart
  • 2014-04-28 14:23
  • 11500
    个人资料
    • 访问:49976次
    • 积分:1330
    • 等级:
    • 排名:千里之外
    • 原创:79篇
    • 转载:12篇
    • 译文:0篇
    • 评论:29条
    个人专属
    文章分类
    最新评论