从零开始学C++之STL(六):变动性算法源代码分析与使用示例(copy_backward、 transform、 replace_copy_if 等)

首先回顾前面的文章,我们把for_each 归类为非变动性算法,实际上它也可以算是变动性算法,取决于传入的第三个参数,即函数

针。如果在函数内对容器元素做了修改,那么就属于变动性算法。


变动性算法源代码分析与使用示例:


一、copy、copy_backward

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// TEMPLATE FUNCTION copy
template< class _InIt,  class _OutIt,  class _InOutItCat>
inline
_OutIt __CLRCALL_OR_CDECL _Copy_opt(_InIt _First, _InIt _Last, _OutIt _Dest,
                                    _InOutItCat, _Nonscalar_ptr_iterator_tag, _Range_checked_iterator_tag)
{
     // copy [_First, _Last) to [_Dest, ...), arbitrary iterators
    _DEBUG_RANGE(_First, _Last);
     for (; _First != _Last; ++_Dest, ++_First)
        *_Dest = *_First;
     return (_Dest);
}

template< class _InIt,  class _OutIt>
inline
_IF_CHK(_OutIt) __CLRCALL_OR_CDECL copy(_InIt _First, _InIt _Last, _OutIt _Dest)
{
     // copy [_First, _Last) to [_Dest, ...)
     return (_Copy_opt(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Dest,
                      _Iter_random(_First, _Dest), _Ptr_cat(_First, _Dest), _Range_checked_iterator_tag()));
}

// TEMPLATE FUNCTION copy_backward
template< class _BidIt1,  class _BidIt2,  class _InOutItCat>
inline
_BidIt2 __CLRCALL_OR_CDECL _Copy_backward_opt(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest,
        _InOutItCat, _Nonscalar_ptr_iterator_tag, _Range_checked_iterator_tag)
{
     // copy [_First, _Last) backwards to [..., _Dest), arbitrary iterators
    _DEBUG_RANGE(_First, _Last);
     while (_First != _Last)
        *--_Dest = *--_Last;
     return (_Dest);
}

template <  class _BidIt1,
          class _BidIt2 >  inline
_IF_CHK(_BidIt2) __CLRCALL_OR_CDECL copy_backward(_BidIt1 _First, _BidIt1 _Last, _BidIt2 _Dest)
{
     // copy [_First, _Last) backwards to [..., _Dest)
     return _Copy_backward_opt(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Dest,
                              _Iter_random(_First, _Dest), _Ptr_cat(_First, _Dest), _STD _Range_checked_iterator_tag());
}

copy 调用了_Copy_opt,在此函数内递增迭代器,从前两个参数指定的区间内取出元素并拷贝到对应_Dest位置上。


for (; _First != _Last; ++_Dest, ++_First)


        *_Dest = *_First;


copy_backward 调用了_Copy_backward_opt,与copy 不同的是实现反向拷贝,即从尾端开始拷贝,所以是递减迭代器。


while (_First != _Last)


        *--_Dest = *--_Last;


示例代码1:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include 
#include 
#include 
#include 
using  namespace std;

void print_element( int n)
{
    cout << n <<  ' ';
}

void add_3( int &n)
{
    n +=  3;
}

int main( void)
{
     int a[] = {  12345 };
    vector< int> v(a, a +  5);
    list< int> l( 15);

    for_each(v.begin(), v.end(), print_element);
    cout << endl;

    for_each(v.begin(), v.end(), add_3);

    for_each(v.begin(), v.end(), print_element);
    cout << endl;

    for_each(l.begin(), l.end(), print_element);
    cout << endl;

    copy(v.begin(), v.end(), l.begin());
    for_each(l.begin(), l.end(), print_element);
    cout << endl;

    copy_backward(v.begin(), v.end(), l.end());
    for_each(l.begin(), l.end(), print_element);
    cout << endl;

     return  0;
}

从零开始学C++之STL(六):变动性算法源代码分析与使用示例(copy_backward、 transform、 replace_copy_if 等)_第1张图片


二、transfrom

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

// TEMPLATE FUNCTION transform WITH UNARY OP
template< class _InIt,  class _OutIt,  class _Fn1,  class _InOutItCat>
inline
_OutIt _Transform(_InIt _First, _InIt _Last, _OutIt _Dest, _Fn1 _Func,
                  _InOutItCat, _Range_checked_iterator_tag)
{
     // transform [_First, _Last) with _Func
    _DEBUG_RANGE(_First, _Last);
    _DEBUG_POINTER(_Dest);
    _DEBUG_POINTER(_Func);
     for (; _First != _Last; ++_First, ++_Dest)
        *_Dest = _Func(*_First);
     return (_Dest);
}

template< class _InIt,  class _OutIt,  class _Fn1>
inline
_IF_CHK(_OutIt) transform(_InIt _First, _InIt _Last, _OutIt _Dest, _Fn1 _Func)
{
     return _Transform(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Dest, _Func,
                      _Iter_random(_First, _Dest), _STD _Range_checked_iterator_tag());
}


// TEMPLATE FUNCTION transform WITH BINARY OP
template< class _InIt1,  class _InIt2,  class _OutIt,  class _Fn2,  class _InItCats,  class _InOutItCat>
inline
_OutIt _Transform(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2,
                  _OutIt _Dest, _Fn2 _Func,
                  _InItCats, _InOutItCat,
                  _Range_checked_iterator_tag, _Range_checked_iterator_tag)
{
     // transform [_First1, _Last1) and [_First2, _Last2) with _Func
    _DEBUG_RANGE(_First1, _Last1);
    _DEBUG_POINTER(_Dest);
    _DEBUG_POINTER(_Func);
     for (; _First1 != _Last1; ++_First1, ++_First2, ++_Dest)
        *_Dest = _Func(*_First1, *_First2);
     return (_Dest);
}


template< class _InIt1,  class _InIt2,  class _OutIt,  class _Fn2,  class _InOutItCat>
inline
_OutIt _Transform(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2,
                  _OutIt _Dest, _Fn2 _Func,
                  random_access_iterator_tag, _InOutItCat,
                  _Range_checked_iterator_tag, _Range_checked_iterator_tag)
{
     // transform [_First1, _Last1) and [_First2, _Last2) with _Func
     // for range checked iterators, this will make sure there is enough space
    _InIt2 _Last2 = _First2 + (_Last1 - _First1);
    (_Last2);
     return _Transform(_First1, _Last1, _CHECKED_BASE(_First2),
                      _Dest, _Func,
                      forward_iterator_tag(), forward_iterator_tag(),
                      _Range_checked_iterator_tag(), _Range_checked_iterator_tag());
}


template< class _InIt1,  class _InIt2,  class _OutIt,  class _Fn2>
inline
_IF_CHK2_(_InIt2, _OutIt, _OutIt) transform(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2,
        _OutIt _Dest, _Fn2 _Func)
{
     return _Transform(_CHECKED_BASE(_First1), _CHECKED_BASE(_Last1), _First2, _Dest, _Func,
                      _Iter_random(_First1, _First2), _Iter_random(_First1, _Dest),
                      _STD _Range_checked_iterator_tag(), _STD _Range_checked_iterator_tag());
}

实际上transfrom 重载了两个版本,一个是四个参数的,即将前两个参数指定区间内的元素执行某种操作(函数内)后拷贝到第三个


参数指示的区间上。而另一个版本是五个参数的,即将两个区间的对应元素进行某种操作后拷贝到第三个区间上去。核心的代码区


别在于下面两行:


*_Dest = _Func(*_First);


*_Dest = _Func(*_First1, *_First2);


示例代码2:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include 
#include 
#include 
#include 
using  namespace std;

void print_element( int n)
{
    cout << n <<  ' ';
}

int fun( int a)
{
     return  2 * a;
}

int fun2( int a,  int b)
{
     return a + b;
}

int main( void)
{
     int a[] = {  12345 };
    vector< int> v(a, a +  5);

    list< int> l( 5);
    list< int> ll( 2);

    transform(v.begin(), v.end(), l.begin(), fun);
    for_each(l.begin(), l.end(), print_element);
    cout << endl;

    transform(v.begin(), v.begin() +  2, v.begin() +  3, ll.begin(), fun2);
    for_each(ll.begin(), ll.end(), print_element);
    cout << endl;

     return  0;
}

输出为 :

2 4 6 8 10

5 7


三、replace、replace_copy、replace_copy_if

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

// TEMPLATE FUNCTION replace
template <  class _FwdIt,
          class _Ty >  inline
void _Replace(_FwdIt _First, _FwdIt _Last,
               const _Ty &_Oldval,  const _Ty &_Newval)
{
     // replace each matching _Oldval with _Newval
    _DEBUG_RANGE(_First, _Last);
     for (; _First != _Last; ++_First)
         if (*_First == _Oldval)
            *_First = _Newval;
}

template <  class _FwdIt,
          class _Ty >  inline
void replace(_FwdIt _First, _FwdIt _Last,
              const _Ty &_Oldval,  const _Ty &_Newval)
{
     // replace each matching _Oldval with _Newval
    _Replace(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Oldval, _Newval);
}


// TEMPLATE FUNCTION replace_copy
template< class _InIt,  class _OutIt,  class _Ty,  class _InOutItCat>
inline
_OutIt _Replace_copy(_InIt _First, _InIt _Last, _OutIt _Dest,
                      const _Ty &_Oldval,  const _Ty &_Newval,
                     _InOutItCat, _Range_checked_iterator_tag)
{
     // copy replacing each matching _Oldval with _Newval
    _DEBUG_RANGE(_First, _Last);
    _DEBUG_POINTER(_Dest);
     for (; _First != _Last; ++_First, ++_Dest)
        *_Dest = *_First == _Oldval ? _Newval : *_First;
     return (_Dest);
}

template <  class _InIt,
          class _OutIt,
          class _Ty >  inline
_IF_CHK(_OutIt) replace_copy(_InIt _First, _InIt _Last, _OutIt _Dest,
                              const _Ty &_Oldval,  const _Ty &_Newval)
{
     // copy replacing each matching _Oldval with _Newval
     return _Replace_copy(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Dest, _Oldval, _Newval,
                         _Iter_random(_First, _Dest), _STD _Range_checked_iterator_tag());
}



// TEMPLATE FUNCTION replace_copy_if
template< class _InIt,  class _OutIt,  class _Pr,  class _Ty,  class _InOutItCat>
inline
_OutIt _Replace_copy_if(_InIt _First, _InIt _Last, _OutIt _Dest,
                        _Pr _Pred,  const _Ty &_Val, _InOutItCat, _Range_checked_iterator_tag)
{
     // copy replacing each satisfying _Pred with _Val
    _DEBUG_RANGE(_First, _Last);
    _DEBUG_POINTER(_Dest);
    _DEBUG_POINTER(_Pred);
     for (; _First != _Last; ++_First, ++_Dest)
        *_Dest = _Pred(*_First) ? _Val : *_First;
     return (_Dest);
}


template <  class _InIt,
          class _OutIt,
          class _Pr,
          class _Ty >  inline
_IF_CHK(_OutIt) replace_copy_if(_InIt _First, _InIt _Last, _OutIt _Dest,
                                _Pr _Pred,  const _Ty &_Val)
{
     // copy replacing each satisfying _Pred with _Val
     return _Replace_copy_if(_CHECKED_BASE(_First), _CHECKED_BASE(_Last), _Dest, _Pred, _Val,
                            _Iter_random(_First, _Dest), _STD _Range_checked_iterator_tag());
}

replace 带4个参数,将前两个参数指示的区间元素值为_Oldval 的替换成_Newval。


   if (*_First == _Oldval)


            *_First = _Newval;


replace_copy 带5个参数,先判断前两个参数指示区间的元素是否是_Oldval,若是则替换成_Newval 赋值到第三个参数指示的区间上,否则直接赋值


*_Dest = *_First == _Oldval ? _Newval : *_First;  


replace_copy_if 带5个参数,在每个元素拷贝时先判断是否满足条件(函数返回为真),满足则替换成_Val,否则保持不变。


*_Dest = _Pred(*_First) ? _Val : *_First;



示例代码3:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include 
#include 
#include 
#include 
using  namespace std;

void print_element( int n)
{
    cout << n <<  ' ';
}

bool fun( int a)
{
     return a <  10;
}

int main( void)
{
     int a[] = {  12343 };
    vector< int> v(a, a +  5);
    list< int> l( 5);

    replace(v.begin(), v.end(),  313);
    for_each(v.begin(), v.end(), print_element);
    cout << endl;

    replace_copy(v.begin(), v.end(), l.begin(),  133);
    for_each(v.begin(), v.end(), print_element);
    cout << endl;

    for_each(l.begin(), l.end(), print_element);
    cout << endl;

    replace_copy_if(v.begin(), v.end(), l.begin(), fun,  0);
    for_each(l.begin(), l.end(), print_element);
    cout << endl;


     return  0;
}

输出为:

1 2 13 4 13

1 2 13 4 13

1 2  3  4  3

0 0 13 0 13


参考:

C++ primer 第四版
Effective C++ 3rd
C++编程规范


你可能感兴趣的:(从零开始学C++,从零开始学C++)