Effective_STL 学习笔记(四十三) 尽量用算法调用代替手写循环

每一个算法接受至少一对用来指示将被操作对象区间的迭代器,比如,min_element 可以找出此区间中的最小的值,而 accumulate 则对区间内的元素作某种形式的整体求和运算,partition 将区间内的元素分割为满足和不满足某某判决条件的两个部分。算法执行时,他们进行检查指示给它的区间中的每一个元素,并且按照所期望的方式进行: 从区间中的起点循环到结束点。有一些算法,比如 find 和 find_if,可能在遍历完成前就返回了,但是即使是这些算法,内部都包含一个循环。

算法内部是一个循环,STL 的广泛涉及面意味着,很多要用循环实现的任务,可以改用算法实现。

1   class Widget
2   {
3   public:
4     void redraw() const;
5     . . .
6   }

使用循环

1   list<Widget> lw;
2   . . .
3   for(list<Widget>::iterator i = lw.begin(); i != lw.end(); i++)
4     i->redraw();

使用 for_each 算法

1   for_each( lw.begin(), lw.end(), mem_fun_ref(&Widget::redraw) );

有三个理由:

  效率: 算法通常比程序员产生的循环更高效

  正确性: 写循环时比调用算法更容易产生错误

  可维护性: 算法通常使代码比相应的显示循环更干净、更直观

效率:算法往往比循环减少了大量的函数调用次数(上例中,多次调用 lw.begin()),STL实现者知道 begin 和 end 用的很频繁,多以尽可能把他们实现得最高效,几乎肯定的是 inline 它们。实现者可以利用知道的容器具体实现优势,用库的使用者无法采用方式来优化遍历。所有STL算法使用的计算机科学都比一般的 C++ 程序员能拿的出的算法更复杂。几乎不可能被打败的 sort 及同组算法(比如,stable_sort(), nth_element()等);适用于有序区间的搜索算法(比如,binary_search, lower-bound等);就算很平凡的任务,比如从连续内存容器中除去一些对象,使用 erase-remove 惯用法都比绝大多数程序员写得更高效.

正确性:写循环时,比麻烦的事在于确保所有使用的迭代器(a)有效,并且(b)指向所期望的地方,假设有一个数组,想获得每一个元素,把它加上41,然后将结果插入一个 deque 的前端

1   size_t fillArray( double* pArray, size_t arraySize );//函数向数组写入数据,返回写入double个数
2   double data[maxNumDoubles];  
3   deque<double> d;
4   . . .
5   size_t numDoubles = fillArray( data, maxNumDoubles );
6   for(size_t i = 0; i < numDoubles; i++)
7     d.insert( d.begin(), data[i] + 41 );  // 每个数据在 d 的前端插入 data[i] + 41        
8                               // 这段代码有一个bug!

这可以执行,但是插入元素与在 data 中对应的元素是反序的

不想反序可能想这样修改:

1   deque<double>::iterator insertlocation = d.begin();  // 记下d的起始迭代器
2   for( size_t; i < numDoubles; i++ )
3     d.insert( insertLocation++, data[i] + 41 );// 插入data[i]+41,然后insertLocation递增
4                                // 这段代码也有 bug

这样使得每次调用 deque::insert 后,都导致所有指向 deque 内部的迭代器失效

改为:

1     deque<double>::iterator insertlocation = d.begin();
2     for( size_t i = 0; i < numDoubles; i++ )
3     {
4         insertLocation = d.insert( insertLocation, data[i] + 41 );
5       ++insertLocation;
6     }

调用算法 transform:

1   transform(data, data+numDoubles, inserter(d, d.begin()), bind2nd(plus<double>(), 41));

把迭代器扔给算法,让他们考虑操纵迭代器时的各种诡异

  

猜你喜欢

转载自www.cnblogs.com/kidycharon/p/10052365.html
今日推荐