STL之iterators和traits
迭代器(iterators)定义:提供一种方法,使之能够依序访问某个聚合物(容器)所含的各个元素,而又无需暴露该聚合物 的内部表述方式
STL中心思想在于将数据容器(containers)和算法(algorithms)分开,彼此独立设计,最后再以迭代器撮合在一起。
迭代器是一种smart pointer
迭代器是一种行为类似于指针的对象。最重要的操作就是内容提领(deference)和成员访问(member access),因此,
迭代器最重要的编程工作就是对operator*和operator->进行重载工作。auto_ptr用来包装原生指针(native pointer)的对象,
声名狼藉的内存泄露(memory leak)问题可藉此获得解决。auto_ptr用法如下,和原生指针一模一样
void fun { auto_ptr<string> ps(new string("fei")); cout << *ps << endl; cout << ps->size() << endk; } // 离开不需要delete,auto_ptr会自动释放内存
注意:auto_ptr角括号内放的是“原生指针所指对象”的类型,而不是原生指针的类型
内容提领deference,对应是 reference 的逆操作,通俗讲就是解引用
迭代器相应类型
C++只支持sizeof,并未支持typeof()。即便动用RTTI性质中的typeid,获得的也只是类型名称,不能拿来做变量声明用。
解决办法:模板的参数推导机制
template<class I, class T> void func_impl(I iter,T t) { T tmp; //这里解决了问题。T就是迭代器所指之物的类型。本例中为 int // ...这里做原本func()应该做的全部工作 } template<class I> inline void func(I iter) { func_impl(iter,*iter); } int main() { int i; func(&i); }
根据经验,最常用的相应类型有五种。value type,difference type, pointer,reference,iterator_catagoly
然而并非任何情况都可以通过template参数推导机制来获取。我们需要更全面的解法(Traits)
迭代器所指对象的类型,称为该迭代器的value type。
偏特化:针对任何template参数更进一步的条件限制所设计出来的一个特化版本
偏特化解决原生指针(比如int*)不是一种class type的问题,也可被萃取类型int
template
template<typename T> class C<T*> {...}; // 这个特化版本仅适用于“T为原生指针”的情况 // “T为原生指针”便是“T为任何型别”的一个更进一步的条件限制
上面用偏特化解决了原生指针的问题,那么新的问题又来了,当原生指针指向的是一个常数对象会得到什么结果
会得到 const int,那么T = const int,即定义了一个无法赋值的局部变量,这显然不行!
解决方法也简单,再实现一个偏特化版本针对const int做处理
template<class T> struct iterator_traits<const T*> { typedef T value_type; // 注意是T而不是const T };总结
- 至此,迭代器的神秘面纱就被解开了,它是一个抽象的存在。它是什么,取决于容器怎么实现它
- 有了模板,我们可以将算法和特定的数据分离开来,而有了迭代器,我们可以将算法和特定的容器分离开来
- 设计适当的相应类型(associated types),是迭代器的责任。
- 设计适当的迭代器,则是容器的责任,唯容器本身知道什么样的迭代器来遍历自己,并执行迭代器该有的各种行为。
- 当然,若要这个“特性萃取机traits”能够有效运作,每一个迭代器必须遵守约定,自行以内嵌类型定义的方式定义出相应类型,
谁不遵守这个约定,就不能兼容STL这个大家庭:)!