STL算法 — copy

为了效率,copy算法可谓无所不用其极,通过分析copy算法能够体会STL的精妙。

首先是三个对外接口:

template <class InputIterator, class OutputIterator>  // 泛化版本
inline OutputIterator copy(InputIterator first, InputIterator last,
                           OutputIterator result)
{
  return __copy_dispatch<InputIterator,OutputIterator>()(first, last, result);
}

inline char* copy(const char* first, const char* last, char* result) {  // 针对原生指针的重载
  memmove(result, first, last - first);
  return result + (last - first);
}

inline wchar_t* copy(const wchar_t* first, const wchar_t* last,        // 针对原生指针的重载
                     wchar_t* result) {
  memmove(result, first, sizeof(wchar_t) * (last - first));
  return result + (last - first);
}

如果传入的迭代器是字符型的原生指针,那么直接使用底层的memmove拷贝,效率是非常高的,但如果是普通的迭代器,则需要进一步分析了。再看看__copy_dispatch函数,此函数又兵分三路,包括一个泛化版本和两个偏特化版本:

template <class InputIterator, class OutputIterator>     // 泛化版本
struct __copy_dispatch
{
  OutputIterator operator()(InputIterator first, InputIterator last,
                            OutputIterator result) {
    return __copy(first, last, result, iterator_category(first));
  }
};

template <class T>
struct __copy_dispatch<T*, T*>     // 特化版本
{
  T* operator()(T* first, T* last, T* result) {
    typedef typename __type_traits<T>::has_trivial_assignment_operator t;
    return __copy_t(first, last, result, t());
  }
};

template <class T>
struct __copy_dispatch<const T*, T*>     // 特化版本
{
  T* operator()(const T* first, const T* last, T* result) {
    typedef typename __type_traits<T>::has_trivial_assignment_operator t;
    return __copy_t(first, last, result, t());
  }
};

首先分析泛化版本。如果迭代器仍为普通迭代器,则调用泛化版本。它要根据迭代器的类型(输入或随机)调用不同的函数:

template <class InputIterator, class OutputIterator>
inline OutputIterator __copy(InputIterator first, InputIterator last,
                             OutputIterator result, input_iterator_tag)     // 输入迭代器
{
  for ( ; first != last; ++result, ++first)
    *result = *first;
  return result;
}

template <class RandomAccessIterator, class OutputIterator>
inline OutputIterator
__copy(RandomAccessIterator first, RandomAccessIterator last,
       OutputIterator result, random_access_iterator_tag)                // 随机迭代器
{
  return __copy_d(first, last, result, distance_type(first));
}

由于输入迭代器的移动只能靠operator++,所以采用逐个赋值。如果是随机迭代器,则继续往下调用:

template <class RandomAccessIterator, class OutputIterator, class Distance>
inline OutputIterator
__copy_d(RandomAccessIterator first, RandomAccessIterator last,
         OutputIterator result, Distance*)
{
  for (Distance n = last - first; n > 0; --n, ++result, ++first)
    *result = *first;
  return result;
}

这里之所以要再单独定义一个函数是因为下述的原生指针版本也可能会调用它。由于是随机迭代器,所以它是以n是否大于0为循环判断条件。相比于输入迭代器的判断条件first != last,这个版本显然效率是要高一些的。这就充分利用了迭代器之间的区别尽可能的进行效率优化。

下面分析两个特化版本。当迭代器为原生指针时,调用__copy_t,它的第三个参数是用来判断指针所指类型是否真的需要用复制操作符来一个个复制(也就是判断是trivial还是non-trivial),这种判断工作就交给了类型萃取器__type_traits来完成。

根据是否需要单独复制可以把__copy_t分成两个版本:

template <class T>
inline T* __copy_t(const T* first, const T* last, T* result, __true_type) {     // trivial
  memmove(result, first, sizeof(T) * (last - first));
  return result + (last - first);
}

template <class T>
inline T* __copy_t(const T* first, const T* last, T* result, __false_type) {    // non-trivial
  return __copy_d(first, last, result, (ptrdiff_t*) 0);
}

trivial版本就很容易了,直接memmove,不需要做过多的复制动作。而non-trivial版本的拷贝则需要逐一进行。由于原生指针属于随机迭代器,所以它可以退而求其次,调用刚才介绍的__copy_d函数。

至此,一个既支持泛化,又具有极高效率的copy函数诞生了!

参考:

《STL源码剖析》 P314.

STL算法 — copy,布布扣,bubuko.com

时间: 2024-08-05 11:16:45

STL算法 — copy的相关文章

STL算法之函数copy

STL算法之copy copy(beg, end, dest) //dest表示输入迭代器 #include <iostream> #include <algorithm> #include <vector> using namespace std; int main() { int myints[] = { 10, 20, 30, 40, 50, 60, 70 }; vector<int> myvector; vector<int>::iter

STL源代码分析——STL算法sort排序算法

前言 因为在前文的<STL算法剖析>中,源代码剖析许多,不方便学习,也不方便以后复习.这里把这些算法进行归类,对他们单独的源代码剖析进行解说.本文介绍的STL算法中的sort排序算法,SGI STL中的排序算法不是简单的高速排序,而是交叉利用各种排序:堆排序.插入排序和高速排序:这样做的目的是提高效率.针对数据量比較大的採用高速排序,数据量比較小的能够採用堆排序或插入排序. 本文介绍了有关排序的算法random_shuffle.partition.stable_partition.sort.s

STL 算法[转 ]

STL 算法 STL算法概述 简介: STL算法部分主要由头文 件<algorithm>,<numeric>,<functional>组成.要使用 STL中的算法函数必须包含头文件<algorithm>,对于数值算法须包 含<numeric>,<functional>中则定义了一些模板类,用来声明函数对象 注意: 编译器无法检测出所传递的迭代器是一个无效形式的迭代器,当然也无法给出算法函数错误的提示,因为迭代器并不是真实的类别,它只是

C++提高5 STL算法 :查找,统计,排序,拷贝,替换,算术,集合 |STL 案例:学校演讲比赛介绍

[本文谢绝转载] <大纲> STL 算法 查找算法 adjacent_find()查找容器中重复元素的首地址 distance()根据迭代器,返回元素的下标 binary_search()二分查找:在有序的序列 find   查找函数 find_if 自定义查找函数 统计算法 count 返回容器中相同元素的个数 cout_if 统计大于3的元素个数 排序算法 marge()对两个有序容器组合到另一个容器 sort 自定义排序 random_shuffle 随机洗牌 基本数据类型 random

STL源码剖析——STL算法之merge合并算法

前言 由于在前文的<STL算法剖析>中,源码剖析非常多,不方便学习,也不方便以后复习,这里把这些算法进行归类,对他们单独的源码剖析进行讲解.本文介绍的STL算法中的merge合并算法.源码中介绍了函数merge.inplace_merge.并对这些函数的源码进行详细的剖析,并适当给出使用例子,具体详见下面源码剖析. merge合并算法源码剖析 // merge, with and without an explicitly supplied comparison function. //将两个

STL源码剖析——STL算法stl_algo.h

前言 在前面的博文中剖析了STL的数值算法.基本算法和set集合算法,本文剖析STL其他的算法,例如排序算法.合并算法.查找算法等等.在剖析的时候,会针对函数给出一些例子说明函数的使用.源码出自SGI STL中的<stl_algo.h>文件.注:本文的源码非常多,可能后续博文会对这些算法进行归类分析. STL算法剖析 #ifndef __SGI_STL_INTERNAL_ALGO_H #define __SGI_STL_INTERNAL_ALGO_H #include <stl_heap

STL源码剖析——STL算法之sort排序算法

前言 由于在前文的<STL算法剖析>中,源码剖析非常多,不方便学习,也不方便以后复习,这里把这些算法进行归类,对他们单独的源码剖析进行讲解.本文介绍的STL算法中的sort排序算法,SGI STL中的排序算法不是简单的快速排序,而是交叉利用各种排序:堆排序.插入排序和快速排序:这样做的目的是提高效率,针对数据量比较大的采用快速排序,数据量比较小的可以采用堆排序或插入排序.注意:STL的sort排序算法的迭代器必须是随机访问迭代器. sort排序算法剖析 // Return a random n

实战c++中的vector系列--vector的遍历(stl算法、vector迭代器(不要在循环中判断不等于end())、operator[])

遍历一个vector容器有很多种方法,使用起来也是仁者见仁. 通过索引遍历: for (i = 0; i<v.size(); i++) { cout << v[i] << " "; } 迭代器遍历: for (vInt::const_iterator iter = v.begin(); iter != v.end();iter++) { cout << *iter << " "; } 算法遍历: copy(v.b

【STL源码学习】STL算法学习之二

第一章:前言 学习笔记,记录学习STL算法的一些个人所得,在以后想用的时候可以快速拾起. 第二章:明细 copy 函数原型: template <class InputIterator, class OutputIterator> OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result); 函数作用: 将[first,last)区间的元素拷贝至result开头的迭代器区间,并返回赋值