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)

Traits编程技法(iterator_traits)--STL源代码门钥

迭代器所指对象的类型,称为该迭代器的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这个大家庭:)!