石狮网站建设报价,wordpress4.9.4源码,网络公司网站建设方案,如何写一个ios的appiterator模式定义如下#xff1a;提供一种方法#xff0c;使之能够依序巡访某个 聚合物(容器)所含的各个元素#xff0c;而又无需暴露该聚合物的内部表述方式.STL的中心思想在于#xff1a;将数据容器(containers)和算法(algorithms)分开#xff0c;彼此独立设计#xff…iterator模式定义如下提供一种方法使之能够依序巡访某个 聚合物(容器)所含的各个元素而又无需暴露该聚合物的内部表述方式.STL的中心思想在于将数据容器(containers)和算法(algorithms)分开彼此独立设计最后再以一帖胶着剂将它们撮合在一起。容器和算法的泛型化从技术角度来看并不困难C 的class templates和 function templates可分别达成目标。如何设计出两者之间的良好胶着剂才是大难题。迭代器 (iterator ) 是一种 smart pointer
迭代器是一种行为类似指针的对象,而指针的各种行为中最常见也最重要的便是内容提领〈dereference)和成员访问(member access) , 因此迭代器最重要的 编程工作就是对 operator* 和 operator- 进行重载(overloading) 工作。关于 这一点C标准程序库有一个auto_ptr可供我们参考任何一本详尽的C 语法书籍都应该谈到auto_ptr 这是一个用来包装原生指 针 (native pointer)的对象声名狼藉的内存漏洞(memory leak)问题可藉此获得解决. auto_ptr用法如下和原生指针一模一样函数第一行的意思是以算式new动态配置一个初值为jjhou” 的 string 对象并将所得结果(一个原生指针)作为aUtojtrStrin g 对象的初值。注意, auto_ptr角括号内放的是“原生指针所指对象”的型别而不是原生指针的型别. 迭代器相 应 型 别 ( associated types ) 我们以func ()为对外接口却把实际操作全部置于func_impl()之中.由于 func_impl ()是一个function template,—旦被调用编译器会自动进行template参数推导。于是导出型别T,顺利解决了问题。迭代器相应型别(associatedtypes)不 只 是 “迭代器所指对象的型别”〜种而 已。根据经验最常用的相应型别有五种然而并非任何情况下任何一种都可利用上述的template参数推导机制来取得.我们需要更全面的解法。
Traits编程技法— STL源代码门钥
迭代器所指对象的型别称为该迭代器的value iy p e .上述的参数型别推导 技巧虽然可用于value ty p e ,却非全面可用万一 value typ e 必须用于函数的传 回值就束手无策了毕竟函数的*template参数推导机制”推而导之的只是参数无法推导函数的回返值型别。我们需要其它方法。声明内嵌型别似乎是个好主意像这样注 意 func ( ) 的回返型别必须加上关键词typename , 因 为 T 是一个 template参数在它被编译器具现化之前编译器对T 一无所悉换句话说编 译器此时并不知道MyIterT: : value_type代表的是一个型别或是一个member function或是一个data m e m b e r . 关 键 词 typename的用意在于告诉编译器这是一个型别如此才能顺利通过编译。大致的意义是如 果 class template拥有一个以上的 template参数我们可以针对其中某个(或数个但非全部)template参数进行特化工作。换句话说我们可以在泛化设计中提供一个特化版本也就是将泛化版本中的某些template参数赋予明确的指定。多了一层间接性先前使用一个T现在使用了两个T但这除了多一层间接性又带来什么好处呢好处是traits可以拥有特化版本。现在我们令 iterator_traites 拥有一个 partial specializations 如下于是原生指针i n t * 虽然不是一种class type,亦可通过traits取 其 value type。这就解决了先前的问题。但是请注意针 对 “指向常数对象的指针(pointeEo-snst) ”下面这个 式子得到什么结果iterator_traitsconst int*::value_type获得的是const i n t 而非i n t . 这是我们期望的吗我们希望利用这种机制来声 明一个暂时变量使其型别与迭代器的value type相同而现在声明一个无法 赋 值 (因 c o n s t 之故)的暂时变量没什么用因此如果迭代器是个pointer-to-const,我们应该设法令其value t y p e 为一个non-const型别。没问题只要另外设计一个特化版本就能解决这个问题现在不论面对的是迭代器My I t e r , 或是原生指针i n t * 或 const int*,都可以通过traits取出正确的(我们所期望的)value type。 特性萃取机”角色萃取各个迭代器的特性。 这里所谓的迭代器特性指的是迭代器的相应型别(associated types)。当然若 要 这 个 “特性萃取机” traits能够有效运作每一个迭代器必须遵循约定自行以内嵌型别定义(nested typedef)的方式定义出相应型别(associated types) 。这是一个约定谁不遵守这个约定谁就不能兼容于S T L 这个大家庭。根据经验最常用到的迭代器相应型别有五种value 1ype, difference iype, pointer, reference, iterator catagoly。如果你希望你所开发的容器能与STL水乳交融一定要为你的容器的迭代器定义这五种相应型别。 “特性萃取机” traits会很 •实地将原汁原味榨取出来3.4.2 迭 代 器 相应型别之二difference type
difference type用来表示两个迭代器之间的距离因此它也可以用来表示一个 容器的最大容量因为对于连续空间的容器而言头尾之间的距离就是其最大容量.如果一个泛型算法提供计数功能例如STL的 count(), 其传回值就必须使用迭代器的 difference type针对相应型别difference type, traits的如下两个(针对原生指针而写的)特 化版本以 C内建的ptrdiff_t (定义于cstddef头文件)作为原生指针的 difference typeptrdiff_t是C/C标准库中定义的一个与机器相关的数据类型。ptrdiff_t类型变量通常用来保存两个指针减法操作的结果3.4.3 迭代器相应型别之三reference type
从 “迭代器所指之物的内容是否允许改变”的角度观之迭代器分为两种不 允 许 改 变 “所指对象之内容”者称为constant iterators,例 如 const int*pic 允许改变所指对象之内容”者称 为 mutable iterators, 例 如 int* pio当我们对 一 个 mutable iterators进行提领操作时获得的不应该是一个右值(rvalue), 应该是一个左值(lvalue), 因为右值不允许赋值操作(assignm ent), 左值才允许在 C 中函数如果要传回左值都是以by reference的方式进行所以当p 是 个 mutable iterators时,如果其value type 是 T,那 么 * p 的型别不应该是T, 应该是T将此道理扩充如果p 是 一 个 constant iterators,其 value type 是 t ,那 么 * p 的型别不应该是const T , 而应该是const T。这里所讨论的* p 的型 别即所谓的reference type
迭代器相应型别之四pointer type
pointers和 references在 C 中有非常密切的关联。如 果 “传回一个左值, 令它代表P 所指之物”是可能的那 么 “传回一个左值令它代表P 所指之物的地址”也一定可以。也就是说我们能够传回一个pointer,指向迭代器所指之物。item 便是 Listlier 的 reference type ,而 item * 便是其 pointer type迭代器 相 应 型 别 之 五 iterator_category
最后一个第五个迭代器的相应型别会引发较大规模的写代码工程。在那之前我必须先讨论迭代器的分类根据移动特性与施行操作迭代器被分为五类尽量针对图3・ 2中的某种迭代器提供一个明确定义并针对更强化的某种迭代器提供另一种定义这样才能在不同情况下提供最大效率。在研究STL的过程中每一分每一秒我们都要谨记在心效率是个重要课题。假设有个算法可接受Forward Iterator,你 以 Random Access Iterator喂给它, 它当然也会接受因为一个Random Access Iterator必然是一个Forward Iterator见图3-2 。但是可用并不代表最佳
以 advanced。 为例
拿 advance 来 说 这是许多算法内部常用的一个函数该函数有两个 参数迭代器P 和数值n;函数内部将p 累进n 次 前进n 距离。下面有三份定义一份针对 Input Iterator, 一份针对 Bidirectional Iterator,另一份针对 Random Access Iteratoro倒是没有针对Foiv/ardlterator而设计的版本因为那和 针 对 Inputiterator而设计的版本完全~致。设计考虑如下如 果 traits有能力萃取出迭代器的种类我们便可利用这个 “迭代器类型”相应型别作为advanced 0 的第三参数。这个相应型别一定必须是一个class type,不能只是数值号码类的东西因为编译器需仰赖它(一个型别)来进行重载决议(overloaded resolution) o 下面定义五个classes,代表五种迭代器类型这 些 classes只作为标记用所以不需要任何成员。至于为什么运用继承机制 稍后再解释。现在重新设计— advance。 (由于只在内部使用所以函数名称加 上特定的前导符)并加上第三参数使它们形成重载注意上述语法每个— advanced 的最后一个参数都只声明型别并未指定 参数名称因为它纯粹只是用来激活重载机制函数之中根本不使用该参数。如果硬要加上参数名称也可以画蛇添足罢了。行进至此还需要一个对外开放的上层控制接口调用上述各个重载的_advance()。这一上层接口只需两个参数当它准备将工作转给上述的 _advance ()时才自行加上第三参数迭代器类型。因此这个上层函数必须有 能力从它所获得的迭代器中推导出其类型—— 这份工作自然是交给traits机制任何一个迭代器其类型永远应该落在“该迭代器所隶属之各种类型中最强化的那个”。例如,int* 既是 Random Access Iterator又是 Bidirectional Iterator, 同时也是Forward Iterator,而且也是Input Iterator,那么其类型应该归属为 random_access_iterator_tag 按 说 advanced()既然可以接受各种类型的迭代器就不应将其型别参数命 名为Inputiterator。这其实是STL算法的一个命名规则以算法所能接受之最 低阶迭代器类型来为其迭代器型别参数命名。消 除 单纯传递调用的函数以 class来定义迭代器的各种分类标签不仅可以促成重载机制的成功运作 (使编译器得以正确执行重载决议overloaded resolution), 另一个好处是通过继承我们 可 以 不 必 再 写 “单纯只做传递调用”的函数(例如前述的 advance() Forwarditerator版 ) 。为什么能够如此考虑下面这个小例子从其输出结果可以 看出端倪以 d is ta n c e ()为 例
关 于 “迭代器类型标签”的应用以下再举一例。distance ()也是常用的一个迭代器操作函数用来计算两个迭代器之间的距离。针对不同的迭代器类型它可以有不同的计算方式带来不同的效率。整个设计模式和前述的advance ()如出一辙distance使用 category动态适配 InputIterator和randomAccessiterator分别调用与之匹配的__distance函数但是这个 distance使用的时候 需要指定最小的迭代器类型来为迭代器进行命名注意,distanced可接受任何类型的迭代器其 template型别参数之所以命 名 为 Inputiterator,是为了遵循STL算法的命名规则以算法所能接受之最初 级类型来为其迭代器型别参数命名.此外也请注意由于迭代器类型之间存在着继承关系 “传递调用(forwarding) ”的行为模式因此自然存在一 一点我已在 前一节讨论过。换句话说当客端调用distanced并使用Output Iterators或Forward Iterators 或 BidirectionaI Iterators 时统统都会传递调用 Input Iterator 版 的那个_ distance ( ) 函数。
std::iterator 的保证
了符合规范任何迭代器都应该提供五个内嵌相应型别以利于traits萃取否则便是自别于整个STL架构可能无法与其它STL组件顺利搭配。然而写代码难免挂一漏万谁也不能保证不会有粗心大意的时候。如果能够将事情简化就好多了。STL提供了一个iterators class如下如果每个新设计的迭代器都 继承自它就可保证符合STL所需之规范设计适当的相应型别(associated types) , 是迭代器的责任。设计适当的迭代 器则是容器的责任.唯容器本身才知道该设计出怎样的迭代器来遍历自己并执行迭代器该有的各种行为(前进、后退、取值、取用成员…) 。至于算法完全可以独立于容器和迭代器之外自行发展只要设计时以迭代器为对外接口就行。
ite ra to r源代码完整重列
SGI STLstl_iterator.h头文件内与本章相关的程序代码。该头文件还有其它内容是关于 iostream iterators, inserter iterators 以及 reverse iterators 的实现将于第8 章讨论。我并不是很懂为啥要再包装一层 SGI STL 的 私 房 菜 __type_traits
traits编程技法很棒适度弥补了 C语言本身的不足。STL只对迭代器加 以规范制定出itera to r_ tra its这样的东西。SG I把这种技法进一步扩大到迭 代器以外的世界于是有了所谓的_ type_tra-itso 双底线前缀词意指这是SGI STL内部所用的东西不在STL标准规范之内 iterator_ traits负责萃取迭代器的特性—type_ traits则负责萃取型别(type)的特性此处我们所关注的型别特性是指这个型别是否具备non-trivial defaltctor ? 是否具备 non-trivial copy ctor ? 是否具备 non-trivial assignment operator?是否具备non-trivial dtor?如果答案是否定的我们在对这个型别进行构造、析构、拷贝、赋值等操作时就可以采用最有效率的措施(例如根本不调用身居高位不谋实事的那些constructor, destructor), 而采用内存直接处理操作如 malloc. memcpy等等获得最高效率。这对于大规模而操作频繁的容器, 有着显著的效率提升4。我们希望上述式子响应我们“真”或 “假”(以便我们决定采取什么策略)但其结果不应该只是个bool值应该是个有着真/假性质的“对象”因为我们 希望利用其响应结果来进行参数推导而编译器只有面对Class object形式的参数, 才会做参数推导。为此上述式子应该传回这样的东西为了达成上述五个式子— type_traits内必须定义一些typedefs,其值不是 _ true_type 就是 _ false_type下面是 SGI 的做法
POD 例子