迭代器
STL的中心思想是:将数据容器和算法分隔开,彼此独立设计,最后再用黏合剂将它们撮合在一起。容器和算法的泛型化,可以用C++的class template和function template来实现,而二者的黏合剂就是迭代器了。
STL将迭代器的实现交给了容器,每种容器都会以嵌套的方式在内部定义专属的迭代器。各种迭代器的接口相同,内部实现却不相同。
迭代器实际上就是一个封装了指针的类模板,类似于智能指针,定义在每个容器类模板里面,所有的迭代器都重载了指针的一些基本操作如*、->、++、==、!=,还有一些根据它的迭代器种类,重载的指针运算符 ++ -- += 等等,里面还typedef了一些别的信息,然后泛型算法通过重载工具函数,还有一个通用的接口函数,实现在编译期决定调用哪个工具函数,使得泛型算法的效率得到提升。
其实我看了 stl_list和stl_vector的源码,vector里面干脆用的是就是原生指针 T *,而list里面 迭代器也不是定义在class list里面,而是在list外面,定义了一个struct __list_iterator 模板,而且在class list里面有个typedef __list_iterator<T, T&, T*> iterator;
并且iterator里面也没有 typedef T value_type; 反而是定义在list里面,anyway,反正都差不多。
迭代器有以下5种类型
input 只能向前移动 只读 所指物只能读取一次
output 只能向前移动 只写 所指物只能写一次
forward 只能向前移动 可读写 所指物能读写多次
bidirectional 能双向移动 可读写 所指物能读写多次
random access 能跳着移动 可读写 所指物能读写多次 注意 原生指针正是这种类型
c++ 定义了 5种struct 分别对应上面的 并且 除了output 下面的迭代器 继承上面的迭代器 (effective cpp p228)
traits
1. 总结:
利用内嵌型别(typedef)和编译器template参数推导功能,获取某些类型信息
加一个中间层 iterator_traits 并且运用模板偏特化技术 实现让原生指针也是一种迭代器的问题
运用重载实现函数和,统一了接口函数,再加上用迭代器的种类变为一个类,也就是使用对象(假如使用函数,那就会是在运行期才会决定调用哪个重载函数 maybe 我猜的),实现在编译期获得信息,决断具体调用哪个函数的能力。
最终的目的就是为了根据获得的类型信息 提升泛型算法的效率!
2. 详细:
traits就像一个萃取机一样,去榨取特征
允许你在编译期间取得某些类型信息,并且对于内置类型(如指针)和用户自定义类型的表现一样好。
它的目的是 比如迭代器trait,我们可以根据迭代器的某些类型信息(并且可以在编译期就获得,而不用typeid,在运行期再决定),对于同一个泛型算法,能够根据这些类型信息做不同的操作,比如一个算法要求 iterator 前进n步,对于一般的迭代器只能一次一次+1,但是对于random access可以一次+n,算法的效率就更高。
为什么要加个traits类,主要就是为了解决原生指针也是种迭代器的问题,不然直接在用户自定义类型里面typedef 内嵌型别就ok了
对于 iterator_traits的实现方式:对于用户自定义类型 也就是iterator类型,在定义迭代器的时候(每一种容器有自己的迭代器类型,所以迭代器是定义在容器定义里面的,也就是实现形式是内嵌类)
typedef xx_tag iterator_category ( xx_tag 也是个struct 就是迭代器的分类),然后在定义一个iterator_traits<typename iter>的类模板,在里面再
typedef typename iter:: iterator_category iterator_category
而对于内置类型,也就是指针, 对iterator_traits 进行一个偏特化,也就是
iterator_traits< iter *>和 iterator_traits<const iter *>
在定义迭代器里面我们要typedef 5种类型信息:
1) value_type
2) iterator_category
3) difference_type
4) pointer
5) reference
用法举例 iterator_traits<iter>::difference_type
另外还有type_traits,在c++11里面,好像获得了支持,我看侯捷说的,但是一些简单的is_void这些简单的traits实现细节跟iterator的5个traits思想是一样的,但是复杂的如is_pod,is_trivial_xx 这些怎么实现的 源码没有,maybe是编译器参与的功劳。
另附参考:虽然我觉得写的不好,我也没看过,但假如以后2刷的时候,可以看看
https://blog.csdn.net/wutao1530663/article/details/64922389