在STL中,容器跟算法是分开设计的,算法是通过迭代器来对容器进行操作的。

在算法运用迭代器的时候,可能会用到其相应的型别,例如返回值为容器中元素的型别,又或者说根据迭代器的类型来选择更好的算法等等。

为了实现这一点,还有为了兼容内置型别的迭代器(vector迭代器直接使用原生pointer),STL使用了traits技法,用于提取迭代器的特性(相应的型别)。

1.首先在iterator中typedef相应的型别

 // 这是迭代器的基类 所有迭代器必须定义这5种型别
template<class Category, class T, class Distance = ptrdiff_t,
class Pointer = T*, class Reference = T&>
struct iterator {
typedef Category iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef Pointer pointer;
typedef Reference reference;
};

2.定义萃取器iter_traits

 // 以迭代器为模板参数,用于萃取相应的型别
template <class Iterator>
struct iter_traits {
typedef typename Iterator::iterator_category iterator_category;
typedef typename Iterator::value_type value_type;
typedef typename Iterator::difference_type difference_type;
typedef typename Iterator::pointer pointer;
typedef typename Iterator::reference reference;
};

3.定义相应的偏特化版本(这就是为什么要使用iter_traits封装多一层),因为内置型别的迭代器并不是class,不能定义相应的型别。

 // 原生指针的偏特化版
template <class T>
struct iter_traits<T*> {
typedef typename random_access_iter_tag iterator_category;
typedef typename T value_type;
typedef typename ptrdiff_t difference_type;
typedef typename T* pointer;
typedef typename T& reference;
}; // 原生const的偏特化版
template <class T>
struct iter_traits<const T*> {
typedef typename random_access_iter_tag iterator_category;
typedef typename T value_type;
typedef typename ptrdiff_t difference_type;
typedef typename const T* pointer;
typedef typename const T& reference;
};

4.5种迭代器类型,只是一个标志,用于根据萃取出来的iterator_category来选择相应的算法。

 struct input_iter_tag {};
struct output_iter_tag {};
struct forward_iter_tag : public input_iter_tag {};
struct bidirectional_iter_tag : public forward_iter_tag {};
struct random_access_iter_tag : public bidirectional_iter_tag {};

下面是distance()的实现,展示了怎么使用traits萃取相应的型别。

 // input迭代器只支持operator++
template<class InputIterator>
inline typename iter_traits<InputIterator>::difference_type
__distance(InputIterator first, InputIterator last, input_iter_tag)
{
iter_traits<InputIterator>::difference_type n = ;
while (first != last)
{
first++;
n++;
}
return n;
} // random access迭代器支持迭代器之间的加减法
template<class RandomAccessIterator>
inline typename iter_traits<RandomAccessIterator>::difference_type
__distance(RandomAccessIterator first, RandomAccessIterator last, random_access_iter_tag)
{
return last - first;
} // 根据迭代器的iterator_category来调用适合的版本
template<class Iterator>
inline typename iter_traits<Iterator>::difference_type
distance(Iterator first, Iterator last)
{
return __distance(first, last, iter_traits<Iterator>::iterator_category());
}

STL的__type_traits也是使用traits技法,它可以萃取一个class是否有不重要的构造函数、是否为POD类型等等。

 // __type_traits也是运用traits技术
struct __true_type {};
struct __false_type {}; template <class type>
struct __type_traits {
// 默认为false 可以实现自己的偏特化版本
// 内置类型的偏特化版本定义在stl_config.h中 都是__true_type
typedef __false_type has_trivial_default_constructor;
typedef __false_type has_trivial_copy_constructor;
typedef __false_type has_trivial_assignment_operator;
typedef __false_type has_trivial_destructor;
typedef __false_type is_POD_type;
};

自定义的类型可以定义相应的偏特化版本,例如定义is_POD_type为__true_type,STL会在元素析构的时候只进行内存回收,而不调用析构函数以用来提高效率。

内存基本处理工具

STL定义了五个全局函数,作用于未初始化空间上,同样的它们也是使用了traits技法。

1.construct()跟destroy(),它们定义在stl_construct.h中

2.uninitialized_copy()、uninitialized_fill()、uninitialized_fill_n(),它们定义在stl_uninitialized中

STL源码剖析(迭代器)的更多相关文章

  1. STL源码剖析 迭代器(iterator)概念与编程技法(三)

    1 STL迭代器原理 1.1  迭代器(iterator)是一中检查容器内元素并遍历元素的数据类型,STL设计的精髓在于,把容器(Containers)和算法(Algorithms)分开,而迭代器(i ...

  2. STL源码剖析--迭代器(转)

    一.为什么需要traits编程技术 前面说了很多关于traits的光荣事迹,但是却一直没有介绍traits究竟是个什么东西,究竟是用来干什么的?traits在英文解释中就是特性,下面将会引入trait ...

  3. 【STL 源码剖析】浅谈 STL 迭代器与 traits 编程技法

    大家好,我是小贺. 点赞再看,养成习惯 文章每周持续更新,可以微信搜索「herongwei」第一时间阅读和催更,本文 GitHub : https://github.com/rongweihe/Mor ...

  4. STL"源码"剖析-重点知识总结

    STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1.STL概述 STL提供六大组件,彼此可以组合 ...

  5. 【转载】STL"源码"剖析-重点知识总结

    原文:STL"源码"剖析-重点知识总结 STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点 ...

  6. (原创滴~)STL源码剖析读书总结1——GP和内存管理

    读完侯捷先生的<STL源码剖析>,感觉真如他本人所说的"庖丁解牛,恢恢乎游刃有余",STL底层的实现一览无余,给人一种自己的C++水平又提升了一个level的幻觉,呵呵 ...

  7. STL源码剖析读书笔记之vector

    STL源码剖析读书笔记之vector 1.vector概述 vector是一种序列式容器,我的理解是vector就像数组.但是数组有一个很大的问题就是当我们分配 一个一定大小的数组的时候,起初也许我们 ...

  8. STL"源码"剖析

    STL"源码"剖析-重点知识总结   STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略 ...

  9. 《STL源码剖析》相关面试题总结

    原文链接:http://www.cnblogs.com/raichen/p/5817158.html 一.STL简介 STL提供六大组件,彼此可以组合套用: 容器容器就是各种数据结构,我就不多说,看看 ...

随机推荐

  1. HDU6074 Phone Call (并查集 LCA)

    Phone Call Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)Tota ...

  2. 【kubernetes】ubuntu14.04 64位 搭建kubernetes过程

    背景: Kubernetes介绍:http://kubernetes.io/docs/getting-started-guides/ github地址:https://github.com/kuber ...

  3. 删除Kali Linux多余的系统架构

    删除Kali Linux多余的系统架构   现在大家通常安装的都是Kali Linux 64位操作系统,其架构为amd64.如果要安装运行32位的程序(如wine32),则必须添加32位架构i386. ...

  4. [SRM478]RandomApple

    题意:有$k$种苹果和$n$个箱子,每个箱子中有一些苹果,先等概率选取$n$个箱子组成集合的非空子集,再从选出的苹果中随机选一个,问每种苹果被选中的概率是多少 设箱子$i$有$cnt_{i,j}$个第 ...

  5. 【高斯消元】CDOJ1783 曜酱的线性代数课堂(一)

    高斯消元求逆矩阵板子. #include<cstdio> #include<cmath> #include<algorithm> #include<cstri ...

  6. 兼容各种浏览器下调用iframe里面的函数

    <script type="text/javascript"> var o = $(window.frames["menu"])[0].conten ...

  7. Generator函数(三)

    Generator.prototype.return() 1.Generator函数返回的遍历器对象还有一个return方法,可以返回给定的值,并终结Generator函数的遍历. function* ...

  8. [转][Navicat for MySQL系列]Navicat如何使用(二)

    上一篇经验已经建立了数据连接,这篇我介绍一下Navicat for MySQL的“增删改查”功能是如何操作的. 工具/原料 Navicat for MySQL 10.1.7 数据库操作(基本) 1 远 ...

  9. NHibernate官方文档中文版——批量插入(Batch inserts)

    A naive approach t7o inserting 100 000 rows in the database using NHibernate might look like this: 一 ...

  10. mysql设置远程访问密码

    mysql -u root -p Aaa111222 grant all privileges on *.* to root@'%' identified by 'aaa111222; Quit ln ...