在开始讲迭代器之前,先列举几个例子,由浅入深的来理解一下为什么要设计迭代器。

  1. //对于int类的求和函数
  2. int sum(int *a , int n)
  3. {
  4. int sum = 0 ;
  5. for (int i = 0 ; i < n ; i++) {
  6. sum += *a++;
  7. }
  8. return sum;
  9. }
  10. //对于listNode类的求和函数
  11. struct ListNode {
  12. int val;
  13. ListNode * next;
  14. };
  15. int sum(ListNode * head) {
  16. int sum = 0;
  17. ListNode *p = head;
  18. while (p != NULL) {
  19. sum += p->val;
  20. p=p->next;
  21. }
  22. return sum;
  23. }

针对如上两个函数,我们来谈谈这种设计的缺陷所在:

  • 遍历int数组和单链表listNode时,需要设计两份不一样的sum求和函数,对于STL这样含有大量容器的代码库,针对每一种容器都设计sum的话,过于冗杂
  • 在sum函数中暴露了太多设计细节,如ListNode的节点值类型int,和指向下一个节点的指针next
  • 对于int数组来说,还必须知道数组的大小,以免越界访问
  • 算法的设计过多的依赖容器,容器的改动会造成大量算法函数的随之改动

那么,如何设计才能使得算法摆脱特定容器?如何让算法和容器各自独立设计,互不影响又能统一到一起?本篇博客就带你一窥STL的迭代器设计。

迭代器概述

迭代器是一种抽象的设计概念,在设计模式中是这么定义迭代器模式的,即提供一种方法,使之能够巡访某个聚合物所含的每一个元素,而无需暴露该聚合物的内部表述方式。

不论是泛型思维或STL的实际运用,迭代器都扮演着重要的角色,STL的中心思想就在于:将数据容器和算法分开,彼此独立设计,最后再以一帖胶着剂将它们撮合在一起。

谈到迭代器需要遍历容器就想到指针,的确,迭代器就是一种类似指针的对象,而指针的各种行为中最常见也最重要的就是内容提领(dereference)和成员访问(member access),因此,迭代器最重要的编程工作就是对operator*和operator->进行重载工作。

Traits编程技法

在介绍STL迭代器之前,先来看看Traits编程技法,通过它你能够更好的理解迭代器设计。

template参数推导机制

我们先回过头去看看sum函数,在sum函数中,我们必须知道容器的元素类型,这关系到函数返回值。既然迭代器设计中不能暴露容器的实现细节,那么我们在算法中是不可能知道容器元素的类型,因此,必须设计出一个机制,能够提取出容器中元素的类型。看看如下示例代码:

  1. #include <stdio.h>
  2. #include <iostream>
  3. using namespace std;
  4. //此函数中并不知道iter所指的元素型别,而是通过模板T来获取的
  5. template <class I, class T1 ,class T>
  6. T sum_impl(I iter ,T1 n , T t) {
  7. T sum = 0;//通过模板的特性,可以获取I所指之物的型别,此处为int
  8. //这里做func应该做的工作
  9. for(int i = 0 ; i < n ;i++){
  10. sum+=*iter++;
  11. }
  12. return sum;
  13. }
  14. template <class I , class T1>
  15. inline T1 sum(I iter , T1 n) {//此处暴露了template参数推导机制的缺陷,在型别用于返回值时便束手无策
  16. return sum_impl(iter , n ,*iter);
  17. }
  18. int main() {
  19. int a[5] = {1,2,3,4,5};
  20. int sum1 = sum(a , 5);
  21. cout<<sum1<<endl;
  22. }

上例中通过模板的参数推导机制推导出了iter所指之物的型别(int),于是可以定义T sum变量。

然而,迭代器所指之物的型别并非只是”迭代器所指对象的型别“,最常用的迭代器型别有五种,并非任何情况下任何一种都可利用上述的template参数推导机制来获取,而且对于返回值类型,template参数推导机制也束手无策,因此,Traits技法应运而生,解决了这一难题!

内嵌型别机制

Traits技法采用内嵌型别来实现获取迭代器型别这一功能需求,具体怎么实现的呢?我们看下面的代码:

  1. #include <stdio.h>
  2. #include <iostream>
  3. using namespace std;
  4. //定义一个简单的iterator
  5. template <class T>
  6. struct MyIter{
  7. typedef T value_type; // 内嵌型别声明
  8. T* ptr;
  9. MyIter(T* p =0):ptr(p){}
  10. T& operator*() const {return *ptr;}
  11. };
  12. template <class I>
  13. typename I::value_type // func返回值型别
  14. func(I iter){
  15. return *iter;
  16. }
  17. int main(){
  18. MyIter<int> iter(new int(8));
  19. cout<<func(iter)<<endl;
  20. }

注意,func()函数的返回值型别必须加上关键词typename,因为T是一个template参数,在它被编译器具现化之前,编译器对其一无所知,关键词typename的用意在于告诉编译器这是一个型别,如此才能通过编译。

内嵌型别看起来不错,可以很顺利的提取出迭代器所指型别并克服了template参数推导机制不能用于函数返回值的缺陷。可是,并不是所有的迭代器都是class type,原声指针就不是!如果不是class type,那么就无法声明内嵌型别。但是STL绝对必须接受原生指针作为一个迭代器。因此,必须另行它法!

iterator_traits萃取机

针对原生指针这类特殊情况,我们很容易想到利用模板偏特化的机制来实现特殊声明,在泛化设计中提供一个特化版本。偏特化的定义是:针对任何template参数更进一步的条件限制所设计出来的一个特化版本。这里,针对上面的MyIter设计出一个适合原生指针的特化版本,如下:

  1. template <class T>
  2. struct MyIter <T*>{ //T*代表T为原生指针,这便是T为任意型别的一个更进一步的条件限制
  3. typedef T value_type; // 内嵌型别声明
  4. T* ptr;
  5. MyIter(T* p =0):ptr(p){}
  6. T& operator*() const {return *ptr;}
  7. };

有了上述的介绍,包括template参数推导,内嵌型别,模板偏特化等,下面STL的真正主角要登场了,STL专门设计了一个iterator_traits模板类来”萃取“迭代器的特性。其定义如下:

  1. // 用于traits出迭代其所指对象的型别
  2. template <class I>
  3. struct iterator_traits
  4. {
  5. typedef typename I::value_type value_type;
  6. };

这个类如何完成迭代器的型别萃取呢?我们继续往下看:

  1. template <class I>
  2. typename iterator_traits<I>::value_type // 通过iterator_traits类萃取I的型别
  3. func(I iter){
  4. return *iter;
  5. }

从表面上来看,这么做只是多了一层间接性,但是带来的好处是极大的!iterator_traits类可以拥有特化版本,如下:

  1. //原生指针特化版本
  2. template <class T>
  3. struct iterator_traits <T*>
  4. {
  5. typedef T value_type;
  6. }
  7. //const指针特化版本
  8. template <class T>
  9. struct iterator_traits <const T*>
  10. {
  11. typedef T value_type;
  12. }

于是,原生指针int*虽然不是一种class type,也可以通过traits取其value,到这里traits的思想就基本明了了!下面就来看看STL只能中”萃取机“的源码

  1. // 用于traits出迭代其所指对象的型别
  2. template <class Iterator>
  3. struct iterator_traits
  4. {
  5. // 迭代器类型, STL提供五种迭代器
  6. typedef typename Iterator::iterator_category iterator_category;
  7. // 迭代器所指对象的型别
  8. // 如果想与STL算法兼容, 那么在类内需要提供value_type定义
  9. typedef typename Iterator::value_type value_type;
  10. // 这个是用于处理两个迭代器间距离的类型
  11. typedef typename Iterator::difference_type difference_type;
  12. // 直接指向对象的原生指针类型
  13. typedef typename Iterator::pointer pointer;
  14. // 这个是对象的引用类型
  15. typedef typename Iterator::reference reference;
  16. };
  17. // 针对指针提供特化版本
  18. template <class T>
  19. struct iterator_traits<T*>
  20. {
  21. typedef random_access_iterator_tag iterator_category;
  22. typedef T value_type;
  23. typedef ptrdiff_t difference_type;
  24. typedef T* pointer;
  25. typedef T& reference;
  26. };
  27. // 针对指向常对象的指针提供特化
  28. template <class T>
  29. struct iterator_traits<const T*>
  30. {
  31. typedef random_access_iterator_tag iterator_category;
  32. typedef T value_type;
  33. typedef ptrdiff_t difference_type;
  34. typedef const T* pointer;
  35. typedef const T& reference;
  36. };

对于源码中的五种迭代器型别在下一小节中会有详细说明。

迭代器设计

迭代器型别

value_type

所谓value_type,是指迭代器所指对象的型别,在之前的示例中已经介绍得很清楚了,这里就不再赘述。

difference_type

difference_type用来表示两个迭代器之间的距离,因此它也可以用来表示一个容器的最大容量。下面以STL里面的计数功能函数count()为例,来介绍一下difference_type的用法。

  1. template <class I,class T>
  2. typename iterator_traits<I>::difference_type //返回值类型
  3. count(I first , I end , const T& value){
  4. typename iterator_traits<I>::difference_type n = 0;
  5. for( ; first!=end ; ++first){
  6. if(*first == value) ++n;
  7. }
  8. return n;
  9. }

针对原生指针和原生的const指针,iterator_traits的difference_type为ptrdiff_t(long int),特化版本依然可以采用iterator_traits::difference_type来获取型别。

reference_type

从“迭代器所指之物的内容是否可以改变”的角度可以将迭代器分为两种:

  • const迭代器:不允许改变“所指对象之内容”,例如const int* p
  • mutable迭代器:允许改变“所指对象之内容”,例如int* p

当我们要对一个mutable迭代器进行提领(reference)操作时,获得的不应该是一个右值(右值不允许赋值操作),而应该是一个左值,左值才允许赋值操作。

故:

+ 当p是一个mutable迭代器时,如果其value type是T,那么*p的型别应该为T&;

+ 当p是一个const迭代器时,*p的型别为const T&

pointer type

迭代器可以传回一个指针,指向迭代器所指之物。再迭代器源码中,可以找到如下关于指针和引用的实现:

  1. Reference operator*() const { return *value; }
  2. pointer operator->() const { return &(operator*()); }

在iterator_traits结构体中需要加入其型别,如下:

  1. template <class Iterator>
  2. struct iterator_traits
  3. {
  4. typedef typename Iterator::pointer pointer;
  5. typedef typename Iterator::reference reference;
  6. }
  7. //针对原生指针的特化版本
  8. template <class T>
  9. struct iterator_traits<T*>
  10. {
  11. typedef T* pointer;
  12. typedef T& reference;
  13. };
  14. //针对原生const指针的特化版本
  15. template <class T>
  16. struct iterator_traits<const T*>
  17. {
  18. typedef const T* pointer;
  19. typedef const T& reference;
  20. };

iterator_category

这一型别代表迭代器的类别,一般分为五类:

  • Input Iterator:只读(read only)
  • Output Iterator:只写(write only)
  • Forward Iterator:允许“写入型”算法在此迭代器所形成的区间上进行读写操作
  • Bidirectional Iterator:可双向移动的迭代器
  • Random Access Iterator:前四种迭代器都只供应一部分指针的算数能力(前三种支持operator++,第四种支持operator–),第五种则涵盖所有指针的算数能力,包括p+n,p-n,p[n],p1-p2,p1
  1. // 用于标记迭代器类型
  2. struct input_iterator_tag {};
  3. struct output_iterator_tag {};
  4. struct forward_iterator_tag : public input_iterator_tag {};
  5. struct bidirectional_iterator_tag : public forward_iterator_tag {};
  6. struct random_access_iterator_tag : public bidirectional_iterator_tag {};

迭代器的保证

为了符合规范,任何迭代器都应该提供五个内嵌型别,以利于Traits萃取,否则就自别与整个STL架构,可能无法与其他STL组件顺利搭配。STL提供了一份iterator class如下:

  1. //为避免挂一漏万,每个新设计的迭代器都必须继承自它
  2. template <class Category, class T, class Distance = ptrdiff_t,
  3. class Pointer = T*, class Reference = T&>
  4. struct iterator {
  5. typedef Category iterator_category;
  6. typedef T value_type;
  7. typedef Distance difference_type;
  8. typedef Pointer pointer;
  9. typedef Reference reference;
  10. };

迭代器源码(完整版)

  1. /**
  2. * 用于标记迭代器类型
  3. */
  4. struct input_iterator_tag {};
  5. struct output_iterator_tag {};
  6. struct forward_iterator_tag : public input_iterator_tag {};
  7. struct bidirectional_iterator_tag : public forward_iterator_tag {};
  8. struct random_access_iterator_tag : public bidirectional_iterator_tag {};
  9. /**
  10. * 用于traits出迭代其所指对象的型别
  11. */
  12. template <class Iterator>
  13. struct iterator_traits
  14. {
  15. // 迭代器类型, STL提供五种迭代器
  16. typedef typename Iterator::iterator_category iterator_category;
  17. // 迭代器所指对象的型别
  18. // 如果想与STL算法兼容, 那么在类内需要提供value_type定义
  19. typedef typename Iterator::value_type value_type;
  20. // 这个是用于处理两个迭代器间距离的类型
  21. typedef typename Iterator::difference_type difference_type;
  22. // 直接指向对象的原生指针类型
  23. typedef typename Iterator::pointer pointer;
  24. // 这个是对象的引用类型
  25. typedef typename Iterator::reference reference;
  26. };
  27. /**
  28. * 针对指针提供特化版本
  29. */
  30. template <class T>
  31. struct iterator_traits<T*>
  32. {
  33. typedef random_access_iterator_tag iterator_category;
  34. typedef T value_type;
  35. typedef ptrdiff_t difference_type;
  36. typedef T* pointer;
  37. typedef T& reference;
  38. };
  39. /**
  40. * 针对指向常对象的指针提供特化
  41. */
  42. template <class T>
  43. struct iterator_traits<const T*>
  44. {
  45. typedef random_access_iterator_tag iterator_category;
  46. typedef T value_type;
  47. typedef ptrdiff_t difference_type;
  48. typedef const T* pointer;
  49. typedef const T& reference;
  50. };
  51. /**
  52. * 返回迭代器类别
  53. */
  54. template <class Iterator>
  55. inline typename iterator_traits<Iterator>::iterator_category
  56. iterator_category(const Iterator&)
  57. {
  58. typedef typename iterator_traits<Iterator>::iterator_category category;
  59. return category();
  60. }
  61. /**
  62. * 返回表示迭代器距离的类型
  63. */
  64. template <class Iterator>
  65. inline typename iterator_traits<Iterator>::difference_type*
  66. distance_type(const Iterator&)
  67. {
  68. return static_cast<typename iterator_traits<Iterator>::difference_type*>(0);
  69. }
  70. /**
  71. * 返回迭代器所指对象的类型
  72. */
  73. template <class Iterator>
  74. inline typename iterator_traits<Iterator>::value_type*
  75. value_type(const Iterator&)
  76. {
  77. return static_cast<typename iterator_traits<Iterator>::value_type*>(0);
  78. }

迭代器相关函数设计

distance函数

distance函数用来计算两个迭代器之前的距离。

  • 针对Input Iterator,Output Iterator,Forward Iterator,Bidirectional Iterator来说,必须逐一累加计算距离
  • 针对random_access_iterator来说,支持两个迭代器相减,所以直接相减就能得到距离

其具体实现如下:

  1. /**
  2. * 针对Input Iterator,Output Iterator,Forward Iterator,Bidirectional Iterator
  3. * 这四种函数,需要逐一累加来计算距离
  4. */
  5. template <class InputIterator>
  6. inline iterator_traits<InputIterator>::difference_type
  7. __distance(InputIterator first, InputIterator last, input_iterator_tag)
  8. {
  9. iterator_traits<InputIterator>::difference_type n = 0;
  10. while (first != last) {
  11. ++first; ++n;
  12. }
  13. return n;
  14. }
  15. /**
  16. * 针对random_access_iterator,可直接相减来计算差距
  17. */
  18. template <class RandomAccessIterator>
  19. inline iterator_traits<RandomAccessIterator>::difference_type
  20. __distance(RandomAccessIterator first, RandomAccessIterator last,
  21. random_access_iterator_tag)
  22. {
  23. return last - first;
  24. }
  25. // 入口函数,先判断迭代器类型iterator_category,然后调用特定函数
  26. template <class InputIterator>
  27. inline iterator_traits<InputIterator>::difference_type
  28. distance(InputIterator first, InputIterator last)
  29. {
  30. typedef typename iterator_traits<InputIterator>::iterator_category category;
  31. return __distance(first, last, category());
  32. }

Advance函数

Advance函数有两个参数,迭代器p和n,函数内部将p前进n次。针对不同类型的迭代器有如下实现:

  • 针对input_iterator和forward_iterator,单向,逐一前进
  • 针对bidirectional_iterator,双向,可以前进和后退,n>0和n<0
  • 针对random_access_iterator,支持p+n,可直接计算

其代码实现如下:

  1. /**
  2. * 针对input_iterator和forward_iterator版本
  3. */
  4. template <class InputIterator, class Distance>
  5. inline void __advance(InputIterator& i, Distance n, input_iterator_tag)
  6. {
  7. while (n--) ++i;
  8. }
  9. /**
  10. * 针对bidirectional_iterator版本
  11. */
  12. template <class BidirectionalIterator, class Distance>
  13. inline void __advance(BidirectionalIterator& i, Distance n,
  14. bidirectional_iterator_tag)
  15. {
  16. if (n >= 0)
  17. while (n--) ++i;
  18. else
  19. while (n++) --i;
  20. }
  21. /**
  22. * 针对random_access_iterator版本
  23. */
  24. template <class RandomAccessIterator, class Distance>
  25. inline void __advance(RandomAccessIterator& i, Distance n,
  26. random_access_iterator_tag)
  27. {
  28. i += n;
  29. }
  30. /**
  31. * 入口函数,先判断迭代器的类型
  32. */
  33. template <class InputIterator, class Distance>
  34. inline void advance(InputIterator& i, Distance n)
  35. {
  36. __advance(i, n, iterator_category(i));
  37. }

附加:type_traits设计

iterator_traits负责萃取迭代器的特性;type_traits负责萃取型别的特性。

带你深入理解STL之空间配置器(思维导图+源码)一篇博客中,讲到需要根据对象构造函数和析构函数的trivial和non-trivial特性来采用最有效的措施,例如:如果构造函数是trivial的,那么可以直接采用如malloc()和memcpy()等函数,来提高效率。

例如:如果拷贝一个未知类型的数组,如果其具有trivial拷贝构造函数,那么可以直接利用memcpy()来拷贝,反之则要调用该类型的拷贝构造函数。

type_traits的源代码实现如下:

  1. /**
  2. * 用来标识真/假对象,利用type_traits响应结果来进行参数推导,
  3. * 而编译器只有面对class object形式的参数才会做参数推导,
  4. * 这两个空白class不会带来额外负担
  5. */
  6. struct __true_type{};
  7. struct __false_type{};
  8. /**
  9. * type_traits结构体设计
  10. */
  11. template <class type>
  12. struct __type_traits
  13. {
  14. // 不要移除这个成员
  15. // 它通知能自动特化__type_traits的编译器, 现在这个__type_traits template是特化的
  16. // 这是为了确保万一编译器使用了__type_traits而与此处无任何关联的模板时
  17. // 一切也能顺利运作
  18. typedef __true_type this_dummy_member_must_be_first;
  19. // 以下条款应当被遵守, 因为编译器有可能自动生成类型的特化版本
  20. // - 你可以重新安排的成员次序
  21. // - 你可以移除你想移除的成员
  22. // - 一定不可以修改下列成员名称, 却没有修改编译器中的相应名称
  23. // - 新加入的成员被当作一般成员, 除非编译器提供特殊支持
  24. typedef __false_type has_trivial_default_constructor;
  25. typedef __false_type has_trivial_copy_constructor;
  26. typedef __false_type has_trivial_assignment_operator;
  27. typedef __false_type has_trivial_destructor;
  28. typedef __false_type is_POD_type;
  29. };
  30. // 特化类型:
  31. // char, signed char, unsigned char,
  32. // short, unsigned short
  33. // int, unsigned int
  34. // long, unsigned long
  35. // float, double, long double
  36. /**
  37. * 以下针对C++内置的基本数据类型提供特化版本,
  38. * 使其具有trivial default constructor,
  39. * copy constructor, assignment operator, destructor并标记其为POD类型
  40. */
  41. __STL_TEMPLATE_NULL struct __type_traits<char>
  42. {
  43. typedef __true_type has_trivial_default_constructor;
  44. typedef __true_type has_trivial_copy_constructor;
  45. typedef __true_type has_trivial_assignment_operator;
  46. typedef __true_type has_trivial_destructor;
  47. typedef __true_type is_POD_type;
  48. };
  49. //针对char的特化版本
  50. __STL_TEMPLATE_NULL struct __type_traits<signed char>
  51. {
  52. typedef __true_type has_trivial_default_constructor;
  53. typedef __true_type has_trivial_copy_constructor;
  54. typedef __true_type has_trivial_assignment_operator;
  55. typedef __true_type has_trivial_destructor;
  56. typedef __true_type is_POD_type;
  57. };
  58. //针对unsigned char的特化版本
  59. __STL_TEMPLATE_NULL struct __type_traits<unsigned char>
  60. {
  61. typedef __true_type has_trivial_default_constructor;
  62. typedef __true_type has_trivial_copy_constructor;
  63. typedef __true_type has_trivial_assignment_operator;
  64. typedef __true_type has_trivial_destructor;
  65. typedef __true_type is_POD_type;
  66. };
  67. //针对short的特化版本
  68. __STL_TEMPLATE_NULL struct __type_traits<short>
  69. {
  70. typedef __true_type has_trivial_default_constructor;
  71. typedef __true_type has_trivial_copy_constructor;
  72. typedef __true_type has_trivial_assignment_operator;
  73. typedef __true_type has_trivial_destructor;
  74. typedef __true_type is_POD_type;
  75. };
  76. //针对unsigned short的特化版本
  77. __STL_TEMPLATE_NULL struct __type_traits<unsigned short>
  78. {
  79. typedef __true_type has_trivial_default_constructor;
  80. typedef __true_type has_trivial_copy_constructor;
  81. typedef __true_type has_trivial_assignment_operator;
  82. typedef __true_type has_trivial_destructor;
  83. typedef __true_type is_POD_type;
  84. };
  85. //针对int的特化版本
  86. __STL_TEMPLATE_NULL struct __type_traits<int>
  87. {
  88. typedef __true_type has_trivial_default_constructor;
  89. typedef __true_type has_trivial_copy_constructor;
  90. typedef __true_type has_trivial_assignment_operator;
  91. typedef __true_type has_trivial_destructor;
  92. typedef __true_type is_POD_type;
  93. };
  94. //针对unsigned int的特化版本
  95. __STL_TEMPLATE_NULL struct __type_traits<unsigned int>
  96. {
  97. typedef __true_type has_trivial_default_constructor;
  98. typedef __true_type has_trivial_copy_constructor;
  99. typedef __true_type has_trivial_assignment_operator;
  100. typedef __true_type has_trivial_destructor;
  101. typedef __true_type is_POD_type;
  102. };
  103. //针对long的特化版本
  104. __STL_TEMPLATE_NULL struct __type_traits<long>
  105. {
  106. typedef __true_type has_trivial_default_constructor;
  107. typedef __true_type has_trivial_copy_constructor;
  108. typedef __true_type has_trivial_assignment_operator;
  109. typedef __true_type has_trivial_destructor;
  110. typedef __true_type is_POD_type;
  111. };
  112. //针对unsigned long的特化版本
  113. __STL_TEMPLATE_NULL struct __type_traits<unsigned long>
  114. {
  115. typedef __true_type has_trivial_default_constructor;
  116. typedef __true_type has_trivial_copy_constructor;
  117. typedef __true_type has_trivial_assignment_operator;
  118. typedef __true_type has_trivial_destructor;
  119. typedef __true_type is_POD_type;
  120. };
  121. //针对float的特化版本
  122. __STL_TEMPLATE_NULL struct __type_traits<float>
  123. {
  124. typedef __true_type has_trivial_default_constructor;
  125. typedef __true_type has_trivial_copy_constructor;
  126. typedef __true_type has_trivial_assignment_operator;
  127. typedef __true_type has_trivial_destructor;
  128. typedef __true_type is_POD_type;
  129. };
  130. //针对double的特化版本
  131. __STL_TEMPLATE_NULL struct __type_traits<double>
  132. {
  133. typedef __true_type has_trivial_default_constructor;
  134. typedef __true_type has_trivial_copy_constructor;
  135. typedef __true_type has_trivial_assignment_operator;
  136. typedef __true_type has_trivial_destructor;
  137. typedef __true_type is_POD_type;
  138. };
  139. //针对long double的特化版本
  140. __STL_TEMPLATE_NULL struct __type_traits<long double>
  141. {
  142. typedef __true_type has_trivial_default_constructor;
  143. typedef __true_type has_trivial_copy_constructor;
  144. typedef __true_type has_trivial_assignment_operator;
  145. typedef __true_type has_trivial_destructor;
  146. typedef __true_type is_POD_type;
  147. };
  148. // 针对指针提供特化
  149. template <class T>
  150. struct __type_traits<T*>
  151. {
  152. typedef __true_type has_trivial_default_constructor;
  153. typedef __true_type has_trivial_copy_constructor;
  154. typedef __true_type has_trivial_assignment_operator;
  155. typedef __true_type has_trivial_destructor;
  156. typedef __true_type is_POD_type;
  157. };
  158. // 针对char *, signed char *, unsigned char *提供特化
  159. struct __type_traits<char*>
  160. {
  161. typedef __true_type has_trivial_default_constructor;
  162. typedef __true_type has_trivial_copy_constructor;
  163. typedef __true_type has_trivial_assignment_operator;
  164. typedef __true_type has_trivial_destructor;
  165. typedef __true_type is_POD_type;
  166. };
  167. struct __type_traits<signed char*>
  168. {
  169. typedef __true_type has_trivial_default_constructor;
  170. typedef __true_type has_trivial_copy_constructor;
  171. typedef __true_type has_trivial_assignment_operator;
  172. typedef __true_type has_trivial_destructor;
  173. typedef __true_type is_POD_type;
  174. };
  175. struct __type_traits<unsigned char*>
  176. {
  177. typedef __true_type has_trivial_default_constructor;
  178. typedef __true_type has_trivial_copy_constructor;
  179. typedef __true_type has_trivial_assignment_operator;
  180. typedef __true_type has_trivial_destructor;
  181. typedef __true_type is_POD_type;
  182. };

后记

本篇博客比较枯燥,STL的迭代器中有很多优秀的值得学习的设计方式,如萃取机制,用类继承来定义迭代器类型等,通篇代码比较多,图片讲解较少,只能说迭代器的设计中基本上都是较为繁琐的型别声明和定义,认真看下去的话会收获很多!若有疑惑可以在博文下方留言,我看到会及时帮大家解答!

参考:

+ C++ STL源码剖析

+ STL源码剖析——迭代器

带你深入理解STL之迭代器和Traits技法的更多相关文章

  1. 带你深入理解STL之Vector容器

    C++内置了数组的类型,在使用数组的时候,必须指定数组的长度,一旦配置了就不能改变了,通常我们的做法是:尽量配置一个大的空间,以免不够用,这样做的缺点是比较浪费空间,预估空间不当会引起很多不便. ST ...

  2. 带你深入理解STL之Set和Map

    在上一篇博客带你深入理解STL之RBTree中,讲到了STL中关于红黑树的实现,理解起来比较复杂,正所谓前人种树,后人乘凉,RBTree把树都种好了,接下来就该set和map这类关联式容器来" ...

  3. 带你深入理解STL之Stack和Queue

    上一篇博客,带你深入理解STL之Deque容器中详细介绍了deque容器的源码实现方式.结合前面介绍的两个容器vector和list,在使用的过程中,我们确实要知道在什么情况下需要选择恰当的容器来满足 ...

  4. 带你深入理解STL之RBTree

    最近一直忙于校招的笔试,STL的深入理解系列也耽搁了好几天,再加上!红黑树真的是超级超级难理解,超级超级复杂,参考了好多博客上的大神的理解才稍微明白一点,勉强入个门,下面请以一个菜鸟的角度跟着我一起学 ...

  5. STL源代码剖析(二) - 迭代器与traits技法

    提要 先看一段用迭代器的代码: int a[] = {1, 2, 3, 4, 5}; vector<int> v1( a, a+5); vector<int>::iterato ...

  6. 带你深入理解STL之Deque容器

    在介绍STL的deque的容器之前,我们先来总结一下vector和list的优缺点.vector在内存中是分配一段连续的内存空间进行存储,其迭代器采用原生指针即可,因此其支持随机访问和存储,支持下标操 ...

  7. 带你深入理解STL之List容器

    上一篇博客中介绍的vector和数组类似,它拥有一段连续的内存空间,并且起始地址不变,很好的支持了随机存取,但由于是连续空间,所以在中间进行插入.删除等操作时都造成了内存块的拷贝和移动,另外在内存空间 ...

  8. 带你深入理解STL之空间配置器(思维导图+源码)

    前不久把STL细看了一遍,由于看得太"认真",忘了做笔记,归纳和总结这步漏掉了.于是为了加深印象,打算重看一遍,并记录下来里面的一些实现细节.方便以后能较好的复习它. 以前在项目中 ...

  9. C++ 标准模板库(STL)——迭代器(iterators)的用法及理解

    C++ STL中迭代器(iterators)用于遍历对象集合的元素.由于容器大小随着插入删除等操作动态改变,无法像静态数组那样获取数组长度然后遍历容器里的所有元素:这时就需要迭代器,每次从容器内第一个 ...

随机推荐

  1. codeforces Gym - 100633J Ceizenpok’s formula

    拓展Lucas #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring ...

  2. 【HNOI2004】L语言

    题目描述 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写字母构成.一个单词W也是由若干小写字母构成.一个字典D是若干个单词的 ...

  3. 10-8 uva1262密码

    题意:有两个图,每一列都存在的字母选作密码,就第k大的密码 思路: 找出各个位置上的密码, 假设: 第1个字母只能是{A,C,D,W}, 第2个字母只能是{B,O,P}, 第3个字母只能是{G,M,O ...

  4. [bzoj4908][BeiJing2017]开车

    来自FallDream的博客,未经允许,请勿转载,谢谢. 你有n辆车,分别a1, a2, ..., an位置和n个加油站,分别在b1, b2, ... ,bn .每个加油站只能支持一辆车的加油,所以你 ...

  5. oracle安装过程和创建本地数据库

    环境: win7 64位 工具: PLSQL Developer 百度云下载:链接:https://pan.baidu.com/s/14L3VCG8YwHzpdhEN7ama0w 密码:jlre or ...

  6. P2P技术详解(二):P2P中的NAT穿越(打洞)方案详解

    1.内容概述 P2P即点对点通信,或称为对等联网,与传统的服务器客户端模式(如下图"P2P结构模型"所示)有着明显的区别,在即时通讯方案中应用广泛(比如IM应用中的实时音视频通信. ...

  7. TensorFlow-Bitcoin-Robot:Tensorflow 比特币交易机器人

    简介 一个比特币交易机器人基于 Tensorflow LSTM 模型,仅供娱乐. A Bitcoin trade robot based on Tensorflow LSTM model.Just f ...

  8. python2.7练习小例子(三)

        3):题目:一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少?     程序分析:假设该数为 x.1.则:x + 100 = n2, x + 100 + ...

  9. js匿名函数,闭包

    http://www.cnblogs.com/chenxianbin89/archive/2010/01/28/1658392.html

  10. struts2 Action获取表单传值(属性,类))

    http://blog.csdn.net/sd0902/article/details/8393157 求大神告知两种方法的不同点 都是写个set方法就行了