这些函数都定义在stl_algobase.h里面,使用时只需要包含 algorithm 头文件就行。
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()(first, last, result);
}
在上面的函数调用中,其实是copy调用了一个仿函数,__copy_dispatch是一个结构体,该结构体重载了operator()运算符,__copy_dispatch
是一个__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 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::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的调用结构基本一致,但也有稍许区别:例如
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()(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 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::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;
}
从first开始拷贝,拷贝count个元素到以result为起始地址的空间。函数定义如下:
template <class InputIterator, class Size, class OutputIterator>
inline pair
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 __copy_n(InputIterator first, Size count,
OutputIterator result,
input_iterator_tag) {
for ( ; count > 0; --count, ++first, ++result)
*result = *first;
return pair(first, result);
}
对于随机存取迭代器,因为可以对迭代器随机访问,即 对迭代器加上一个整数,得到另一个迭代器,这样确定了输入区间,就能复用copy()函数了。
template <class RandomAccessIterator, class Size, class OutputIterator>
inline pair
__copy_n(RandomAccessIterator first, Size count,
OutputIterator result,
random_access_iterator_tag) {
RandomAccessIterator last = first + count;
return pair(last,
copy(first, last, result));
}
copy_n的返回值是一个pair,pair的两个元素都是迭代器,
pair::first指向输入区间的后面一个元素;
pair::second指向输出区间的后面一个元素。