STL源码分析之copy算法

Copy ----- 深入强化效率

 

首先,先看看assignment operator(即 operator =) 和拷贝构造函数的区别

第一,  他们是不可能被同时调用的

其次,不管什么构造函数,它只可能在需要构造一个对象的时候被调用,比如:

String s = s1;
String s(s1);

这里调用的是拷贝构造函数,是构造新对象用的

而重载的operator=,完全可以看成一个一般的成员函数。我们也知道在对象还没有构造出来之前,讨论非静态的成员函数时没有意义的,所以operator= 必然是发生在对象生成之后,一次新的赋值

String s;             //默认构造函数
S = s1;                //调用operator = ,因为此时s已经被构造出来了


 

关于copy函数,我们讨论的是operator=

为了提高效率,STL算法用尽办法,包括函数重载,型别特性,偏特化等。

 

 

要注意的是,copy函数的赋值操作可能是向前推进的,即从给定第一个位置开始赋值,不断累加,直到最后。说是可能,是因为函数还可能因为效率问题调用memcpy或是memmove等底层函数。

 

         根据copy函数的赋值进行顺序,函数的结果可能是会出错的。

         如果输入区间和输出区间完全没有重叠,当然毫无问题; 否则如果输出区间的终点在输入区间里面,根据copy的赋值顺序,是不会出现问题的

                                         

然而如果输出区间的起点在输入区间里面,那么因为copy的赋值顺序可能就会造成错误,说是可能,是因为函数可能因为效率而调用memmove等函数,这类函数会事先将区间内容复制下来,所以是不会造成错误的

                                            

 

现在我们来看看copy的源代码实现细节:

template<class InputIterator,  class OutputIterator >
inline OutputIterator copy(InputIteratorfirst, InputIterator last, OutputIterator result )
{
   //要注意的是,这里使用的是仿函数
return __copy_dispatch<InputIterator, OutputIterator>(first,last, result);
}

下面是重载函数,针对原生指针,我们可以视为特殊的迭代器

Iinlne char *copy(const char *first, constchar *last, char *result)
{
memmove(result, first, last-first);
return result+(last-first);
}
 
Iinlne 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);
}

可见,对于普通的char*, wchar* 这种类型的形参类型,都是直接调用的memmove底层函数,对于未知类型的类型则予以更复杂的处理。    

关于memmove,这里给一个简单的解释:

Void * memmove(void *dest, const void *src,size_t count)

函数用于从src拷贝count个字节到dest;

如果目标区域和源区域有重叠的话,此函数能保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,复制后的src也会被更改

如果目标区域与源区域没有重叠,则类似memcpy

 

 

copy的泛化版本中调用的__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,俩参数都是T*指针形式
template<class T>
struct __copy_dispatch<T*, T*>
{
T* operator()(T* first, T* last, T* result )
{
       //可见,这里接下来会根据是否有没有重要的赋值操作使用不同的算法
       typedef typename __type_traits<T>::has_trivial_assignment_operatort;
return __copy_t(first, last, result, t());
}
};
 
//版本2,第一个参数为constT*指针形式,第二个参数为T*形式
template<class T>
struct __copy_dispatch<const T*, T*>
{
   //目的同上
T* operator()(const T* first,const T*last, T*result, t() )
{
    typedef typename__type_traits<T>::has_trivial_assignment_operator t;
    return _copy_t(first,last, result, t());
}
}


走到这里,我们发现,已经分成了两路,一路是根据使用的迭代器,通过类型来挑选不同的算法;一路是根据使用的原生指针,通过判断是否有重要的赋值函数来挑选不同的算法。

 

首先,我们走第一条路看看

这里是在使用迭代器的情况下,对不同类型迭代器的不同操作:

//对于使用的是InputIterator迭代器的容器:
template <class InputIterator, class OutputIterator>
inline OutputIterator__copy(InputIterator first, InputIterator last,
                             OutputIteratorresult, input_iterator_tag)
{
  for ( ; first != last; ++result, ++first)
    *result = *first;
  return result;
}

//对于使用RandomAccessIterator迭代器的容器
template <classRandomAccessIterator, class OutputIterator>
inline OutputIterator
__copy(RandomAccessIteratorfirst, RandomAccessIterator last,
       OutputIterator result,random_access_iterator_tag)
{
    //只是这里又划分出去一个函数,为的是将来可以复用
  return __copy_d(first, last, result, distance_type(first));
}
template <classRandomAccessIterator, class OutputIterator, class Distance>
inline OutputIterator
__copy_d(RandomAccessIteratorfirst, RandomAccessIterator last,
         OutputIterator result, Distance*)
{
    //这个算法和上面这个算法差别在于判断循环停止的条件,一个是通过迭代器是否相等,一个是判断一个整型数大于0,据说是可以提升速率的,毕竟判断迭代器是否相等也要调用一个函数
  for (Distance n = last - first; n > 0; --n, ++result,++first)
    *result = *first;
  return result;
}


接着,我们来走第二条路

这里是在使用原生指针的情况下,判断是否有重要的赋值函数

template <class T>
inline T* __copy_t(const T* first, const T* last, T* result,__true_type) {
    //如果没有什么重要的赋值函数需要执行,那么直接调用memmove
  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) {
    //可以看到,这里使用了上面复用的函数,使用到了operator=
  return __copy_d(first, last, result, (ptrdiff_t*) 0);
}

以上就是所有关于copy的内容了,如果要真的消化这里面的内容,需要对语言的不断认识!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值