【STL】算法 — copy

25 篇文章 0 订阅
24 篇文章 3 订阅
为了效率,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.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值