首页 > 编程知识 正文

迭代器是一种范型,steffensen迭代法

时间:2023-05-06 03:42:21 阅读:148801 作者:1390

文章列表1 .迭代器:智能指针(smart pointer )2.迭代器对应类型(associate types )和类型采用2.1迭代器对应类型概念、应用场景偏向

与OOP(objectorientedprogramming )将数据(数据)和行为(methods )合并在一起的思想不同,STL的中心思想gp (通用程序)是数据容器)

通用汽车的想法具体是,containers和algorithms团队可以关上各自的门制造汽车,在此期间可以通过iterator进行交流。 algorithms在迭代器中决定操作范围,在迭代器中接收容器的数据。 那么,如何设计迭代器是个难题。

1 .迭代器(迭代器)在智能指针(smart pointer )胶着剂就是迭代器(iterator)中,动态内存的管理通过new和delete进行,实际上new和delete运算符最终调用忘记释放会导致内存泄漏,但如果快速释放,即在存在指针引用的情况下释放内存,则会生成引用错误内存的指针。 针对这个问题,智能指针的概念,即智能指针在新的标准库中包含shared_ptr (允许多个指针指向同一对象)、unique_ptr )

迭代器是执行类似指针行为的对象(智能指针对象),因为其行为包括内容提取(deference )和成员访问(member access ),迭代器是操作者

明确上述概念后,请尝试设计单向链表的迭代器。

templatetypenametclasslist { public 3360 void insert _ front (tvalue ) },用于定义单链接列表的基本数据结构; voidinsert_end(tvalue; void display (STD :3360 ostream OS=STD :3360 out ) const; //private:listitemt*_end (; ListItemT* _front (; long _size; (; templatetypenametclasslistitem { public : tvalue () const { return _value; } listitem t * next const { return _ next; }//.private:T _value; ListItemT* _next; (; 请参阅-----------------2.如果要递增迭代器,请返回_next节点//将迭代器转换为多种嵌入数据类型的llx item在单向链表节点中也是双向链表struct ListIter {//这里的迭代器设计为只服务链表//保持与容器的联系(keep a reference to Container ) p=0) :ptr(p ) {} //default ctor//是编译器提供的缺省值,因此不需要实现copy ctor。} item * operator-() const ) returnptr //以下两个操作器是标准做法//(1)预校准操作器() ) ({ ptr=ptr-next ) ); return *this; (//)2) post-incrementoperatorlistiteroperator ) I

nt) { ItemIter tmp = *this; ++*this; return tmp; }bool operator==(const ListIter& i) { return ptr == i.ptr; }bool operator!=(const ListIter& i) { return ptr != i.ptr; }//...};

从以上实现中,可以看到为完成ListIter的设计,其中暴露了许多List的实现细节,包括数据成员ListItem及其成员函数。对于调用者而言,这些都应该是屏蔽掉的。但是要设计出ListIter,就难免暴露出这些实现细节,也就是说要对List有丰富的了解。因此,惯常做法是由容器的设计者开发该容器的迭代器。如此,所有实现细节对使用者屏蔽,这也是为什么每种STL容器都有专属迭代器的原因。

2. 迭代器相应类型(associate types) 及 类型的取用 2.1 迭代器相应类型概念、应用场景 & 偏特化概念

在实际的算法中,在运用迭代器时,会用到迭代器所指对象中的相应类型(associate type)。

那么算法实现中该如何满足 声明一个以“迭代器所指对象(中)的类型”为类型的成员/参数,或返回值是“迭代器所指对象(中)的类型”的类型 的需求呢?

可分为以下三种情况:

① 迭代器所指对象是c++内置类型;② 迭代器所指对象是自定义类型(class type)情形;③ 迭代器所指对象是原生指针(naive pointer)情形;

对应的运用以下三种方法解决:

① function template的参数推导(augument deducation)机制② 声明内嵌类型③ 利用泛化中偏特化(partial secification)(下面有解释)envolve to :萃取机 iterator_traits 机制

注意:这三种方法是逐步整合为最终的实现的方案就是 iterator_traits萃取机 机制,它包含了函数模板的参数推导,声明内嵌类型和偏特化所有内容,也同时解决了以上的三个场景的实现需求。

①声明一个迭代器所指对象的类型为c++内置类型的成员/参数,使用模板函数的推导机制进行,在函数实现过程中加入对底层模板函数的封装; ②返回值是迭代器所指自定义类型(class type)中的内嵌类型,使用关键字typename来声明算法中出现的成员或返回值是迭代器所指对象的内嵌类型。
其中typename用法见typename关键字

需要注意的是,并不是所有的迭代器都是class type的。比如说原生指针(naive pointer),就无法将其定义为内嵌类型。所以还要对上述的一般化概念中的特殊情况做特殊化处理。

③偏特化(template partial specification):如果class template拥有一个以上的template参数,可以对其中某个(或数个,但非全部)template进行特化工作,其中偏特化有两种形式:

1. 对template参数的部分个参数进行特化;2. 对template参数的范围进行限定;

两种形式见下图所示:

偏特化其实就可以理解为“针对任何template参数进一步地进行条件限制所设计出的特化版本”。那么对应的,全特化(full specification) 就是指对模板参数不做任何限制。

如上,利用对(常量)指针类型的偏特化,解决了内嵌类型无法解决的迭代器所指对象是原生指针类型的问题。

2.2 迭代器相关类型的取用——iterator_traits机制

在《Effective C++》条款47:请使用traits classes表现类型信息中对萃取机制也有详细解答,先抛开这些,从头开始讲起。

结合以上三种情况和三种解决方法,最终设计出了迭代器萃取机这一中间层,其作用是萃取出迭代器的相关特性(也即是相应类型的取用),以屏蔽迭代器实现对算法实现的影响。如左下图所示:

iterator_traits示意图,可将算法向迭代器询问的关于容器特性给"萃取"出来 迭代器常用的5种类型在特征萃取机中都有内嵌类型定义

在图中列出了原生指针(pointer),还单独列出了常量指针(pointer-to-const)(对于const关键字的解析见:const限定符)。对于常量指针,泛化版本的iterator::traits<const int*> value_type会返回一个const int,也即返回值是一个无法进行赋值的临时变量,所以针对常量指针的value_type类型应当特化为非常量类型,如下:

template <class T>struct iterator_traits<const T*> { //偏特化版本——当迭代器是一个pointer-to-const时typedef T value_type; //萃取出的类型应当是T而非常量const T//...};//附上指针的偏特化萃取实现struct iterator_traits<T*> {typedef T value_type;//...};

所以只要迭代器的实现者在实现过程中,将内嵌类型和原生类型遵循约定,以内嵌类型(nested typedef)的方式定义(typedef)出STL迭代器萃取机所规定的相关类型,就可以与STL标准实现兼容,实现算法实现和容器实现的剥离。

如右上图(iterator_traits对常用内嵌类型的typedef)所示,迭代器中最常用到的迭代器类型有五种,整理出如下表格:

迭代器相关类型说明value_type所谓value type,指的是迭代器所指对象的类型。任何一个与STL有完美搭配的class,都应该定义value type内嵌类型difference_typedifference type表示两个迭代器之间的距离,因此也可用来表示一个容器的最大容量(头尾距离),以alogrithm中的count()为例:

对于原生指针,c++内建了ptrdiff_t(位于<cstddef>头文件内)作为原生指针的difference type(在iterator_traits<(const) T*>中使用);
当需要迭代器I的difference type,可以写typename iterator_traits<I>::difference_type,如上图中例;reference首先根据迭代器能否更改所指的对象,可以分为constant iterators和mutable iterators两种;
对应两种迭代器:
如果iterator是const的,那么若是其value_type是T,那么返回值应当是const T&;
如果iterator是mutable的,那么若是其value_type是T,那么返回值应当为T&;pointer指向迭代器所指之物/对象的类型的指针的类型;
iterator_category对于迭代器种类,若是良好的利用好category的继承关系,可以极大地提高算法的效率,种类的具体解释和继承关系如下面图中所示。以advance()函数为例可以探讨category对算法的影响,详细内容见《STL源码剖析》p93,运用到了类的多态性,向上类型转换(派生类转基类,is-a继承关系)。 迭代器的5种分类 迭代器的分类和从属关系 3. std::iterator的保证

为符合规范,任何迭代器都应提供五个内嵌相应类别,以利于traits萃取。STL为此提供了一个iterators class,也即std::iterator如下,如果每个新设计的迭代器继承自它,就可保证STL所需之规范:

之前的ListIter可以改写为: template <class Item>struct ListIter : public std::iterator<std::forward_iterator_tag, Item> {//...}; 4. 总结

设计适当的迭代器相应内嵌类型,是迭代器的责任;同时设计适当的迭代器,是容器设计者的责任。

唯有容器本身,才知道应当设计怎样的迭代器来遍历自己,还有如何运用相关的运算符;

有了traits技巧(其利用内嵌类型的编程技巧和template的参数推导功能),增强了c++未能提供的关于类型辨别方面的能力(c++是弱类型语言,能够进行隐式类型转换),完成了算法和容器间的解耦;其实个人感觉,traits技巧很像平台中间件的概念;

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。