find 源码剖析

一:用法解析
函数原型:
template <class InputIterator, class T>
   InputIterator find (InputIterator first, InputIterator last, const T& val);

功能:

查找[ first , last )范围内第一个与val相等的元素,返回其迭代器;若找不到,返回last。

例子:

// find example
#include <iostream>     // std::cout
#include <algorithm>    // std::find
#include <vector>       // std::vector

int main () {
  // using std::find with array and pointer:
  int myints[] = { 10, 20, 30, 40 };
  int * p;

  p = std::find (myints, myints+4, 30);
  if (p != myints+4)
    std::cout << "Element found in myints: " << *p << '\n';
  else
    std::cout << "Element not found in myints\n";

  // using std::find with vector and iterator:
  std::vector<int> myvector (myints,myints+4);
  std::vector<int>::iterator it;

  it = find (myvector.begin(), myvector.end(), 30);
  if (it != myvector.end())
    std::cout << "Element found in myvector: " << *it << '\n';
  else
    std::cout << "Element not found in myvector\n";

  return 0;
}
运行如下:
Element found in myints: 30
Element found in myvector: 30


二:源码剖析
源码方面稍微有点麻烦,待我慢慢道来,先把源码贴上。

// TEMPLATE FUNCTION find
template<class _Ty,
  class _Ignored> inline
  bool _Within_limits(const _Ty& _Val, true_type, true_type, _Ignored)
  { // signed _Elem, signed _Ty
  return (SCHAR_MIN <= _Val && _Val <= SCHAR_MAX);
  }

template<class _Ty> inline
  bool _Within_limits(const _Ty& _Val, true_type, false_type, true_type)
  { // signed _Elem, unsigned _Ty, -1 == static_cast<_Ty>(-1)
  return (_Val <= SCHAR_MAX || static_cast<_Ty>(SCHAR_MIN) <= _Val);
  }

template<class _Ty> inline
  bool _Within_limits(const _Ty& _Val, true_type, false_type, false_type)
  { // signed _Elem, unsigned _Ty, -1 != static_cast<_Ty>(-1)
  return (_Val <= SCHAR_MAX);
  }

template<class _Ty,
  class _Ignored> inline
  bool _Within_limits(const _Ty& _Val, false_type, true_type, _Ignored)
  { // unsigned _Elem, signed _Ty
  return (0 <= _Val && _Val <= UCHAR_MAX);
  }

template<class _Ty,
  class _Ignored> inline
  bool _Within_limits(const _Ty& _Val, false_type, false_type, _Ignored)
  { // unsigned _Elem, unsigned _Ty
  return (_Val <= UCHAR_MAX);
  }

template<class _InIt,
  class _Ty> inline
  bool _Within_limits(_InIt, const _Ty& _Val)
  { // check whether _Val is within the limits of _Elem
  typedef typename remove_pointer<_InIt>::type _Elem;
  return (_Within_limits(_Val, is_signed<_Elem>(), is_signed<_Ty>(),
    integral_constant<bool, -1 == static_cast<_Ty>(-1)>()));
  }

template<class _InIt> inline
  bool _Within_limits(_InIt, const bool&)
  { // bools are always within the limits of _Elem
  return (true);
  }

//-------------------------------------------------------------------------------//
  
template<class _InIt,
  class _Ty> inline5
  _InIt _Find(_InIt _First, _InIt _Last, const _Ty& _Val, true_type)
  { // find first byte matching integral _Val
  if (!_Within_limits(_First, _Val))
    return (_Last);
  _First = static_cast<_InIt>(_CSTD memchr(
    _First, static_cast<unsigned char>(_Val), _Last - _First));
  return (_First ? _First : _Last);
  }

template<class _InIt,
  class _Ty> inline
  _InIt _Find(_InIt _First, _InIt _Last, const _Ty& _Val, false_type)
  { // find first matching _Val
  for (; _First != _Last; ++_First)
    if (*_First == _Val)
      break;
  return (_First);
  }

//-------------------------------------------------------------------------------//

// TEMPLATE CLASS integral_constant
template<class _Ty,
  _Ty _Val>
  struct integral_constant
  { // convenient template for integral constant types
  static _CONST_DATA _Ty value = _Val;

  typedef _Ty value_type;
  typedef integral_constant<_Ty, _Val> type;

  _CONST_FUN operator value_type() const _NOEXCEPT
    { // return stored value
    return (value);
    }

  _CONST_FUN value_type operator()() const _NOEXCEPT
    { // return stored value
    return (value);
    }
  };

typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;

// TEMPLATE CLASS is_same
template<class _Ty1,
  class _Ty2>
  struct is_same
    : false_type
  { // determine whether _Ty1 and _Ty2 are the same type
  };

template<class _Ty1>
  struct is_same<_Ty1, _Ty1>
    : true_type
  { // determine whether _Ty1 and _Ty2 are the same type
  };

template<class _InIt,
  class _Ty> inline
  _InIt _Find(_InIt _First, _InIt _Last, const _Ty& _Val)
  { // find first matching _Val
  // activate optimization for pointers to (const) bytes and integral values
  typedef integral_constant<bool,
    (is_same<_InIt, char *>::value
    || is_same<_InIt, signed char *>::value
    || is_same<_InIt, unsigned char *>::value
    || is_same<_InIt, const char *>::value
    || is_same<_InIt, const signed char *>::value
    || is_same<_InIt, const unsigned char *>::value)
    && is_integral<_Ty>::value
  > _Memchr_opt;
  return (_Find(_First, _Last, _Val, _Memchr_opt()));
  }

template<class _InIt,
  class _Ty> inline
  _InIt find(_InIt _First, _InIt _Last, const _Ty& _Val)
  { // find first matching _Val
  _DEBUG_RANGE(_First, _Last);
  return (_Rechecked(_First,
    _Find(_Unchecked(_First), _Unchecked(_Last), _Val)));
  }
觉得源码挺长的,其实不然,真正的源码比这少了点,我之所以多加了代码是因为find的源码实现调用了其他地方,我也就顺便粘贴过来了。

应该很容易发现,上面的代码我分为了三部分,用两条横线隔开了,为了接下来更清晰的表述,我们姑且从上往下分别命名为:第一部分,第二部分,第三部分。


阅读源码应该从代码底部,一层一层的往上看,好,看源码的最后一个函数,它调用了上一层的函数,那我们再看上一层的函数,有点恐怖的感觉,许多||运算。那我们来看看这个有||运算的函数都做了什么,我可以先告诉你们这个函数是干嘛的,我们知道find函数有三个参数,两个同类型的的迭代器,还有一个特定比较值,那这个有许多||运算的函数其实就是对迭代器的类型做了分类讨论,一共两种情况,一种是指向字符,还有一种不是指向字符的。下面来说下原因。


要理解原因,只要理解两个结构体即可,就是is_same和integral_constant,关于这两个结构体的内容我也贴在源码的第三部分了。我们先来看integral_constant,在这个结构体我们只需关注两句代码,粘贴如下:

static _CONST_DATA _Ty value = _Val;

_CONST_FUN value_type operator()() const _NOEXCEPT
    { // return stored value
    return (value);
    }
第一句,不用解释了,很简单;第二句,仿函数。


我们先跳过这个结构体,再看下面的两句代码:

typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
true_type和false_type都是结构体类型,两句代码形式相似,我们就拿true_type来说吧。注意哦,把模板参数带入结构体我们发现,在true_type中,value已被赋值为true了,而在那个仿函数里,也返回了value(其实也就是true)。那么很容易知道false_type就是做了相反的事。


我们再来看is_same结构体,通过源码我们对这个结构体有两个明显的认识,一是继承了true_type/false_type结构体;二是这个结构体有因为模板参数的不同,有两种形式。通过对这个结构体的注释,我们也很容易知道这个结构体是干嘛的:“ determine whether _Ty1 and _Ty2 are the same type ” 。也就是说,true_type代表了 _Ty1 and _Ty2 are the same type;而false_type代表了different type。


好了,现在我们终于可以回过头看下那个有很多||运算的函数了,它在第三部分。我们再次贴出它的源码:

template<class _InIt,
  class _Ty> inline
  _InIt _Find(_InIt _First, _InIt _Last, const _Ty& _Val)
  { // find first matching _Val
  // activate optimization for pointers to (const) bytes and integral values
  typedef integral_constant<bool,
    (is_same<_InIt, char *>::value
    || is_same<_InIt, signed char *>::value
    || is_same<_InIt, unsigned char *>::value
    || is_same<_InIt, const char *>::value
    || is_same<_InIt, const signed char *>::value
    || is_same<_InIt, const unsigned char *>::value)
    && is_integral<_Ty>::value
  > _Memchr_opt;
  return (_Find(_First, _Last, _Val, _Memchr_opt()));
  }
经过上面对integral_constant和is_same两个结构体的解析,我相信你已经看出端倪了。通过is_same判断_InIt参数类型是不是char *,signed char *,unsigned char *等中的一种,并且,注意还有一个&&运算,还要判断_Ty是否是一个整型。若都满足,就相当于 typedef integral_constant<bool,true> _Memchr_opt,进而利用仿函数作为_Find的第四参数。你可能好奇为什么这么做,请接着看:


现在我们来到源码的第二部分,不用读者急着翻哪个是第二部分的代码,我这里贴在下面,就两个函数:

template<class _InIt,
  class _Ty> inline
  _InIt _Find(_InIt _First, _InIt _Last, const _Ty& _Val, true_type)
  { // find first byte matching integral _Val
  if (!_Within_limits(_First, _Val))
    return (_Last);
  _First = static_cast<_InIt>(_CSTD memchr(
    _First, static_cast<unsigned char>(_Val), _Last - _First));
  return (_First ? _First : _Last);
  }

template<class _InIt,
  class _Ty> inline
  _InIt _Find(_InIt _First, _InIt _Last, const _Ty& _Val, false_type)
  { // find first matching _Val
  for (; _First != _Last; ++_First)
    if (*_First == _Val)
      break;
  return (_First);
  }
注意看这两个函数第四参数,true_type代表_InIt是char *,signed char *,unsigned char *等中的一种,并且_Ty是整型类型的;那么false_type自然是反过来了。

很容易发现第四参数是false_type的,我们很容易看懂代码意思,其实到这里,你已经看到了find函数原始源码实现了,就这么简单。
我们还是重点看第四参数是true_type的,它调用了memchr,这个函数来自头文件<string.h>,读者可以查阅文档,看这个memchr的功能,至此,可以回答上面没解决的一个问题,为什么要分true_type和false_type两种形式的函数,原因很简单,为了效率。这个你只要知道memchr的意思就明白了,话说mem....系列的函数在对字节操作上都很高效,值得源码一探究竟。






源码摘抄自Visual Studio 2015安装目录algorithm文件中。



点击进入目录----> C++源码剖析目录





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值