这些函数都定义在stl_algobase.h里面,使用时只需要包含 algorithm 头文件就行。

copy :

STL 的SGI版本中的copy函数声明如下:

template <class InputIterator, class OutputIterator>
inline OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result) ;

该函数完成的功能:把[first, last)区间的元素拷贝到以result为起始地址的空间中。
以上是copy的泛化版本,除此之外,还有两个特化版本:

inline char* copy(const char* first, const char* last, char* result) ;
inline wchar_t* copy(const wchar_t* first, const wchar_t* last,  wchar_t* result) ;

这两个函数是针对char类型的指针,如果拷贝的是char类型的指针所指向的内存,则直接调用特化版本,这两个函数的内部其实就是调用memmove()函数,然后返回拷贝目的数据区间的下一个位置的地址。

下面先大概图解一下对于copy的具体调用过程。

下面是copy的源码,函数实现定义在stl_algobase.h中: 接下来用源码解释上面这幅函数调用图。
(ps : 在下面的源码中,我用具有指导作用的标题表示他们的调用关系;
例如:copy函数有三个版本,我用1.1表示它的第一个泛化版本,用1.2表示第二个特化版本,用1.3表示它的第三个特化版本,用1.1.1表示__copy_dispatch的第一个泛化版本,依次类推。)

1.1
copy的泛化版本:

template <class InputIterator, class OutputIterator>
inline OutputIterator copy(InputIterator first, InputIterator last,OutputIterator result)
{
  return __copy_dispatch<InputIterator,OutputIterator>()(first, last, result);
}

在上面的函数调用中,其实是copy调用了一个仿函数,__copy_dispatch是一个结构体,该结构体重载了operator()运算符,__copy_dispatch<InputIterator,OutputIterator>()是一个__copy_dispatch类型的匿名对象,该对象能接受first, last, result作为函数参数。
__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));}
};

1.2
copy的特化版本1:

inline char* copy(const char* first, const char* last, char* result) {memmove(result, first, last - first);
  return result + (last - first);
}

1.3
copy的特化版本2:

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);
}

1.1.1
copy内部,__copy_dispatch

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;
}

这个函数的作用是把 [first, last) 区间的元素拷贝到以result为起始地址的内存中,这里有几种情况需要解释下:

1. 如果输出区间的长度大于输入区间,则之后的区间内容不变;
2. 如果输出区间的长度小于输入区间,则会发生不可预测的结果;
3. 这个函数的循环中,使用两个迭代器是否相等来判断循环是否结束,需调用迭代器的operator!=,开销大,速度慢。

copy内部,__copy_dispatch

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));
}

这个特化版本与上个特化版本的区别在于:第一个是接受一个input_iterator_tag类型的参数,而第二个接受一个random_access_iterator_tag类型的参数。
不同的参数内部调用也不同,如果是随机迭代器,则可以把last与first相减得到输入区间的大小,从而避免使用迭代器的 operator!= 比较两个迭代器是否相等。。。
由此也可见copy为了效率,无所不用其极。。。。。

下面是_copy_d的实现(把它单独封装起来,是因为下面还有一个地方会用到这个函数):

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;
}

1.1.2
__copy_dispatch的特化版本1:

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());}
};

__copy_dispatch的特化版本2:

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());}
};

上面两个特化版本针对的是原生指针,对于这种情况,STL调用了__copy_t,下面是其定义:

template <class T>
inline T* __copy_t(const T* first, const T* last, T* result, __true_type) {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) {
  return __copy_d(first, last, result, (ptrdiff_t*) 0);
}

对于__copy_dispatch的2个特化版本,里面用到了 has_trivial_assignment_operator 类型,他本身是一个struct __false_type{}; 或者struct __true_type{}; 类型;
如果是struct __false_type{}; 类型,表示迭代器所指元素的值类型T没有”无关紧要的赋值语句”,就要调用__copy_t(const T* first, const T* last, T* result, __false_type);
如果是struct __true_type{}; 类型,表示迭代器所指元素的值类型T有”无关紧要的赋值语句”,就要调用__copy_t(const T* first, const T* last, T* result, __true_type);

下面是copy的两个特化版本:
由于是char * 类型的参数,所以直接调用库函数memmove来完成。

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);
}

copy_backward :

下面先大概图解一下对于copy_backward的具体调用过程:

copy_backward与copy的调用结构基本一致,但也有稍许区别:例如

1. copy有一个泛化版,两个特化版,而copy_backward只有一个泛化版;
2. copy中的__copy有两个版本,分别用input_iterator_tag和random_access_iterator_tag区分,而copy_backward只有一个__copy_backward泛化版本;

由于copy_backward与copy的结构基本一致,并且比copy要简单许多,这里只给出源码,就不解释了。

template <class BidirectionalIterator1, class BidirectionalIterator2>
inline BidirectionalIterator2 copy_backward(BidirectionalIterator1 first,BidirectionalIterator1 last,BidirectionalIterator2 result) {
  return __copy_backward_dispatch<BidirectionalIterator1,BidirectionalIterator2>()(first, last,result);
}

__copy_backward_dispatch的泛化版本:

template <class BidirectionalIterator1, class BidirectionalIterator2>
struct __copy_backward_dispatch
{BidirectionalIterator2 operator()(BidirectionalIterator1 first,BidirectionalIterator1 last,BidirectionalIterator2 result) {
    return __copy_backward(first, last, result);}
};

__copy_backward_dispatch的特化版本1:

template <class T>
struct __copy_backward_dispatch<T*, T*>
{T* operator()(T* first, T* last, T* result) {typedef typename __type_traits<T>::has_trivial_assignment_operator t;return __copy_backward_t(first, last, result, t());}
};

__copy_backward_dispatch的特化版本2:

template <class T>
struct __copy_backward_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_backward_t(first, last, result, t());}
};

“无关紧要的赋值操作符” 会执行下面这个函数:

template <class T>
inline T* __copy_backward_t(const T* first, const T* last, T* result,__true_type) {const ptrdiff_t N = last - first;memmove(result - N, first, sizeof(T) * N);
  return result - N;
}

没有“无关紧要的赋值操作符” 会执行下面这个函数:

template <class T>
inline T* __copy_backward_t(const T* first, const T* last, T* result,__false_type) {
  return __copy_backward(first, last, result);
}

底层的具体实现之一的函数(另一个是memmove):

template <class BidirectionalIterator1, class BidirectionalIterator2>
inline BidirectionalIterator2 __copy_backward(BidirectionalIterator1 first,BidirectionalIterator1 last,BidirectionalIterator2 result) {while (first != last) *--result = *--last;
  return result;
}

copy_n :

从first开始拷贝,拷贝count个元素到以result为起始地址的空间。函数定义如下:

template <class InputIterator, class Size, class OutputIterator>
inline pair<InputIterator, OutputIterator>
copy_n(InputIterator first, Size count,OutputIterator result) {
  return __copy_n(first, count, result, iterator_category(first));
}

这个函数的关系并不复杂,只是内部调用了一个__copy_n函数。而__copy_n函数只是根据接收到的迭代器型别,执行不同的策略。
比较简单,就不画图了; 下面是源码 :

对于输入型迭代器,因为输入迭代器可以接收前向迭代器、双向迭代器、随机存取迭代器,所以不能唯一确定迭代器型别,需要做最坏打算,就是一个一个地拷贝。

template <class InputIterator, class Size, class OutputIterator>
pair<InputIterator, OutputIterator> __copy_n(InputIterator first, Size count,OutputIterator result,input_iterator_tag) {for ( ; count > 0; --count, ++first, ++result)*result = *first;
  return pair<InputIterator, OutputIterator>(first, result);
}

对于随机存取迭代器,因为可以对迭代器随机访问,即 对迭代器加上一个整数,得到另一个迭代器,这样确定了输入区间,就能复用copy()函数了。

template <class RandomAccessIterator, class Size, class OutputIterator>
inline pair<RandomAccessIterator, OutputIterator>
__copy_n(RandomAccessIterator first, Size count,OutputIterator result,random_access_iterator_tag) {RandomAccessIterator last = first + count;
  return pair<RandomAccessIterator, OutputIterator>(last,copy(first, last, result));
}

copy_n的返回值是一个pair,pair的两个元素都是迭代器,
pair::first指向输入区间的后面一个元素;
pair::second指向输出区间的后面一个元素。

STL算法之 copy、copy_backward、copy_n相关推荐

  1. stl 之 copy copy_backward

    http://blog.csdn.net/jerryjbiao/article/details/7381498 元素复制算法copy 该算法主要用于容器之间元素的拷贝,即将迭代器区间[first,la ...

  2. STL算法algorithm,

    2019独角兽企业重金招聘Python工程师标准>>> STL算法部分主要由头文件<algorithm>,<numeric>,<functional&g ...

  3. STL算法学习[转]

    原文:http://www.cppblog.com/mzty/archive/2007/03/14/19819.html STL算法学习,小结如下: 前提: 下载stl源码:  http://www. ...

  4. 【C++】C++11 STL算法(一):非修改序列操作(Non-modifying sequence operations)

    目录 一.all_of.any_of.none_of: 1.官方说明 2.谓词 3.STL算法对谓词的说明 4.谓词的五种模式 5.all_of (C++ 11) 6.any_of (C++ 11) ...

  5. C++中的STL算法详解

    1.STL算法详解 STL提供能在各种容器中通用的算法(大约有70种),如插入.删除.查找.排序等.算法就是函数模板,算法通过迭代器来操纵容器中的元素.许多算法操作的是容器上的一个区间(也可以是整个容 ...

  6. 大顶堆删除最大值_C++|使用STL算法创建、调整、输出最大堆、最小堆

    最大堆(又叫大根堆.大顶堆)和最小堆是二叉堆的两种形式,一类很重要的数据结构,如用于堆排序等. 最小堆:根结点的键值是所有堆结点键值中最小者,且每个结点的值都比其孩子的值小. 最大堆:根结点的键值是所 ...

  7. STL 算法接口及用法说明 (二)

    STL 算法接口及用法说明 copy copy 有两个重载,意义和用法较为明显,不做过多说明: template<class _InIt, class _OutIt> inline_Out ...

  8. STL::算法::常见算法(二)

    STL::算法::常见算法 remove_copy/remove 及其泛化版 remove_copy_if/remove_if 这两组函数提供的实现删除序列中的相关元素的思路,对我们实现自己的算法是有 ...

  9. STL::算法::常见算法

    总述 定位 泛型编程(GP)走了一条与面向对象编程(OOP)完全不同的道路,各种容器类的设计与实现也没有走严格意义的继承.接口机制.在STL的设计与实现中,算法并非是容器类的成员函数,而是一种搭配迭代 ...

  10. C++ 笔记(19)— 标准模板库(STL容器、STL迭代器、STL算法、STL容器特点、STL字符串类)

    C++ 标准库可以分为两部分: 标准函数库: 这个库是由通用的.独立的.不属于任何类的函数组成的.函数库继承自 C 语言. 面向对象类库: 这个库是类及其相关函数的集合. C++ 标准库包含了所有的 ...

最新文章

  1. VS2012代码提示快捷键
  2. 用GDB调试程序(二)
  3. Oracle 数据表误删恢复 Flashback
  4. 洛谷P2698 [USACO12MAR]花盆Flowerpot
  5. Python 网络爬虫笔记2 -- Requests库实战
  6. 数值分析(part1)--拉格朗日插值
  7. java时间api_什么是java时间API?
  8. 一发工资就全部取出,会对银行流水有影响吗?
  9. Atmosphere 1.0:支持Java/JavaScript的异步通信框架
  10. Android实现按两次back键退出应用
  11. 3说明书_怎么才能做好产品说明书翻译?知行翻译公司总结了3点
  12. 数据库表设计必需元素_HTML5输入,必需,模式,数据列表
  13. 计算机关机后耗电问题,笔记本电脑关机后电池还会耗电怎么解决
  14. MLOps- 吴恩达Andrew Ng Overview of the ML Lifecycle and Deployment Week1 论文等资料汇总
  15. 信号与系统matlab实践实验二,信号与系统matlab实验课后习题答案
  16. Ubuntu20.04安装搜狗拼音
  17. 在C++程序中使用系统热键(附代码)
  18. 客服客户聊天系统源码分享
  19. Informix 常用函数一
  20. 【Matlab文件操作】打开、创建、更改和删除文件与文件夹以及获取文件信息

热门文章

  1. 下载InstallShield Limited Edition for Visual Studio
  2. 相关性分析和假设检验
  3. JAVASE复习计划
  4. 最详细全国区号汇总(json格式)
  5. c语言读取广播星历程序,GPS广播星历计算卫星位置和速度.doc
  6. RS232,RS485简介,以及DB9接口上引脚对应关系
  7. 判定表与判定树的画法_判定树和判定表
  8. 设置服务器网站播放flv视频文件,网页制作 flvplayer.swf无法播放服务器上flv文件 如何设置...
  9. ACDSee将捆绑雅虎助手,广大ACDSee用户有难了
  10. cmd控制台通过sftp命令下载服务器文件