窥视C++细节-STL使用萃取机提高性能

本文分析使用的SGI版的STL。其可读性非常高,提供一个下载链接:

迭代器的种类

STL中有五种迭代器:输入迭代器、输出迭代器、前向迭代器、双向迭代器、随机迭代器。

struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};

在这里插入图片描述

在STL中,使用类的方式表示迭代器种类,使用继承表示迭代器之间的关系。例如随机迭代器一定是一种双向迭代器。

在定义容器迭代器的时候,需要定义它的类型。

template<class T, class Ref, class Ptr>
struct __list_iterator {
...
  /*双向迭代器*/
  typedef bidirectional_iterator_tag iterator_category;    
  typedef T value_type;
  typedef Ptr pointer;
  typedef Ref reference;
...
};

template <class T, class Alloc = alloc>
class list {
...
public:

  /*list容器迭代器*/
  typedef __list_iterator<T, T&, T*>             iterator;           
  typedef __list_iterator<T, const T&, const T*> const_iterator;
  ...
};

list容器内定义的迭代器是bidirectional_iterator_tag类型的,list在实现时,使用的是双向链表。所以它的迭代器可以前后移动。因为list不是连续空间,所以迭代器每次只能移动到相邻的结点,并不能进行跳跃。

struct __deque_iterator {
...
  /*随机迭代器*/
  typedef random_access_iterator_tag iterator_category;          
  typedef T value_type;
  typedef Ptr pointer;
  typedef Ref reference;
...
};

template <class T, class Alloc = alloc, size_t BufSiz = 0> 
class deque {
...
public:  
  /*deque容器迭代器*/
  typedef __deque_iterator<T, T&, T*, BufSiz>  iterator;
  typedef __deque_iterator<T, const T&, const T&, BufSiz>  const_iterator;      

deque容器内的迭代器是random_access_iterator_tag类型的,在访问deque时,可以通过迭代器进行随机的访问deque内的元素。

iterator traits

template <class Iterator>
struct iterator_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;
};

这就是迭代器萃取机,将迭代器丢入萃取机后,就可以获取迭代器相关的信息。

/*获取list<int>中的迭代器的类型为ListIterator*/
typedef list<int>::iterator  ListIterator;

/*将ListIterator丢入萃取机,用于返回ListIterator的类型。*/
typedef iterator_traits<ListIterator>::iterator_category category;

返回的迭代器类型category,实际类型为bidirectional_iterator_tag。

template <class ListIterator>
struct iterator_traits {
  typedef typename ListIterator::iterator_category iterator_category;
  ...
};

使用ListIterator实例化类模板后

/*核心是ListIterator::iterator_category*/
typedef typename ListIterator::iterator_category iterator_category;

ListIterator::iterator_category是核心内容

ListIterator::iterator_category

list<int>::iterator::iterator_category

list<int>::__list_iterator<int, int&, int*>::iterator_category

/*在__list_iterator内对iterator_category类型的定义*/
typedef bidirectional_iterator_tag iterator_category; 

将ListIterator::iterator_category进一步展开,最后得到的结果就是__list_iterator<int, int&, int*>::iterator_category,这就是迭代器的类型。最后可知list<int>::iterator的类型是bidirectional_iterator_tag类型。

distance模板函数

distance函数用于计算两个迭代器之间的距离。
在这里插入图片描述

使用distance(itr1,itr2)计算vector和list迭代器之间的距离,虽然返回结果都是3,但是计算的方式是不同的。

vector内的迭代器是随机类型,计算itr1和itr2的距离,可以使用itr2-itr1直接得到。list的迭代器是双向类型的,不能直接相减,需要从itr1一直遍历到itr2,在遍历的时候,统计遍历元素的个数,就是两个迭代器之间的距离。

template <class InputIterator>
inline iterator_traits<InputIterator>::difference_type
distance(InputIterator first, InputIterator last) 
{
  /*萃取迭代器的类型*/
  typedef typename iterator_traits<InputIterator>::iterator_category category;   
  return __distance(first, last, category());
}

调用distance()函数,第一步先萃取处迭代器的类型,根据迭代器类型不同,进行不同方式的处理。

category就是迭代器的类型,category()是一个临时对象,这个临时对象主要的作用是,是在重载函数中找出匹配的重载函数。

/*迭代器是随机类型*/
template <class RandomAccessIterator>
inline iterator_traits<RandomAccessIterator>::difference_type
__distance(RandomAccessIterator first, RandomAccessIterator last, random_access_iterator_tag) 
{
  return last - first;    /*迭代器之间之间相减*/
}

如果category是RandomAccessIterator类型,则category()生成的临时对象就是RandomAccessIterator类型,那么就能匹配到这个重载函数。

随机类型的迭代器,计算迭代器之间的距离,仅仅是迭代器的相减。

__distance()函数中的random_access_iterator_tag参数,仅用于重载函数的匹配。

/*其他类型的迭代器*/
template <class InputIterator>
inline iterator_traits<InputIterator>::difference_type
__distance(InputIterator first, InputIterator last, input_iterator_tag) 
{
  iterator_traits<InputIterator>::difference_type n = 0;
    
  /*遍历*/
  while (first != last) {
    ++first; ++n;    /*n用于计数*/
  }

  return n;
}

如果category是bidirectional_iterator_tag、forward_iterator_tag、input_iterator_tag类型,则都会匹配到这个重载函数。虽然这个函数的参数的类型是input_iterator_tag,但bidirectional_iterator_tag、forward_iterator_tag是其子类,在没有完全匹配的重载函数时,也是可以匹配这个函数的。

这些类型的迭代器在计算距离时,需要从first迭代器一直遍历到last迭代器。
在这里插入图片描述
迭代器类型不同,分门别类的使用最适合迭代器的方法,可以提高性能。

对随机类型的迭代器使用遍历的方式计算距离,实属浪费。但其他类型的迭代器计算距离,只能使用遍历的方式。

萃取机的偏特化

vector的迭代器就是指针,并不像list、deque那样,是一个单独的类,可以在其内部定义迭代器的类型。

STL中通过iterator_traits偏特化,实现了对vector中纯指针类型迭代器的萃取。

/*偏特化    迭代器萃取机 */
template <class T>
struct iterator_traits<T*> {
  typedef random_access_iterator_tag iterator_category;
  typedef T                          value_type;
  typedef ptrdiff_t                  difference_type;
  typedef T*                         pointer;
  typedef T&                         reference;
};

如果迭代器是一个单纯的指针,那么使用iterator_traits时,会使用这个偏特化版本。

单纯的指针是一种随机类型,可以随便跳跃。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STL是指标准模板库(Standard Template Library),它是C++语言的一部分,提供了一系列的模板类和函数,用于支持通用的数据结构和算法。STL的目标是提供高效、可重用和可扩展的组件,以便开发人员能够更轻松地编写高质量的代码。STL包含了许多常见的数据结构,如vector、list、set、map等,以及各种算法,比如排序、查找、遍历等。通过使用STL,开发人员可以更加高效地处理各种数据结构和算法的问题,提高代码的开发效率和质量。 在STL中,我们可以使用各种容来存储和管理数据。例如,我们可以使用std::map来创建一个键值对的映射,其中每个键都有一个与之相关联的值。下面是一个示例代码,展示了如何创建和使用一个std::map对象: std::map<std::string, int> disMap() { std::map<std::string, int> tempMap{ {"C语言教程",10},{"STL教程",20} }; return tempMap; } std::map<std::string, int> newMap(disMap()); 在这个示例中,disMap()函数创建了一个临时的std::map对象,并初始化了其中的一些键值对。然后,使用移动构造函数将这个临时对象移动到了一个新的std::map对象newMap中。最终,我们可以通过newMap对象来访问和操作这些键值对。 综上所述,STLC++中的标准模板库,提供了一系列的模板类和函数,用于支持通用的数据结构和算法。STL使用可以提高代码的开发效率和质量,并且通过各种容和算法,可以方便地处理各种数据结构和算法的问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [C++ STL详解超全总结(快速入门STL)](https://blog.csdn.net/qq_50285142/article/details/114026148)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [【C++实验】阅读STL源码并分析](https://blog.csdn.net/qq_35760825/article/details/125311509)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值