### Effective STL Item 43：优先使用STL泛型算法以取代手写循环

STL泛型算法vs.手写的循环

Scott Meyers

-------------------------------------------------------------------------------

[这篇文章源自一本即将出版的书。S. Meyers，Effective STL:50 Specific Ways to Improve Your Use of the Standard Template Library，改自Item 26-28（WQ注，CUJ上原文如此，应为Item 43）。 2001 Addison-Wesley。 发行：permission of Pearson Education, Inc]

class Widget {

public:

...

void redraw() const;

...

};

list<Widget> lw;

...

for (list<Widget>::iterator i =

lw.begin();

i != lw.end(); ++i) {

i->redraw();

}

for_each(lw.begin(), lw.end(),

mem_fun_ref(&Widget::redraw));

l 效率：泛型算法通常比循环高效。

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

l 可维护性: 与相应的显式循环相比，泛型算法通常使代码更干净、更直观。

for (list<Widget>::iterator i =

lw.begin();

i != lw.end();

++i) {

i->redraw();

}

// this call evaluates lw.end() exactly

// once

for_each(lw.begin(), lw.end(),

mem_fun_ref(&Widget::redraw));

// C API: this function takes a pointer

// to an array of at most arraySize

// doubles and writes data to it. It

// returns the number of doubles written.

size_t fillArray(double *pArray, size_t arraySize);

// create local array of max possible size

double data[maxNumDoubles];

// create deque, put data into it

deque<double> d;

...

// get array data from API

size_t numDoubles =

fillArray(data, maxNumDoubles);

// for each i in data, insert data[i]+41

// at the front of d; this code has a bug!

for (size_t i = 0; i < numDoubles; ++i) {

d.insert(d.begin(), data[i] + 41);

}

// remember d’s begin iterator

deque<double>::iterator insertLocation = d.begin();

// insert data[i]+41 at insertLocation, then

// increment insertLocation; this code is also buggy!

for (size_t i = 0; i < numDoubles; ++i) {

d.insert(insertLocation++, data[i] + 41);

}

deque<double>::iterator insertLocation =

d.begin();

// update insertLocation each time

// insert is called to keep the iterator valid,

// then increment it

for (size_t i = 0; i < numDoubles; ++i) {

insertLocation =

d.insert(insertLocation, data[i] + 41);

++insertLocation;

}

// copy all elements from data to the

// front of d, adding 41 to each

transform(data, data + numDoubles,

inserter(d, d.begin()),

bind2nd(plus<int>(), 41));

vector<int> v;

int x, y;

...

// iterate from v.begin() until an

// appropriate value is found or

// v.end() is reached

vector<int>::iterator i = v.begin();

for( ; i != v.end(); ++i) {

if (*i > x && *i < y) break;

}

// i now points to the value

// or is the same as v.end()

// find the first value val where the

// "and" of val > x and val < y is true

vector<int> iterator i =

find_if(v.begin(), v.end(),

compose2(logical_and<bool>(),

bind2nd(greater<int>(), x),

bind2nd(less<int>(), y)));

find_if()的调用可以不显得那么复杂，只要将测试的逻辑封装入一个独立的functor(也就是申明了operator()成员函数的类)：

template<typename T>

class BetweenValues:

public std::unary_function<T, bool> {

public:

// have the ctor save the

// values to be between

BetweenValues(const T& lowValue,

const T& highValue)

: lowVal(lowValue), highVal(highValue)

{}

// return whether val is

// between the saved values

bool operator()(const T& val) const

{

return val > lowVal && val < highVal;

}

private:

T lowVal;

T highVal;

};

...

vector<int> iterator i =

find_if(v.begin(), v.end(),

BetweenValues<int>(x, y));

// beginning of function

{

...

template <typename T>

class BetweenValues:

public std::unary_function<T, bool> { ... };

vector<int>::iterator i =

find_if(v.begin(), v.end(),

BetweenValues<int>(x, y));

...

}

// end of function

// beginning of function

{

...

class BetweenValues:

public std::unary_function<int, bool> { ... };

vector<int> iterator i =

find_if(v.begin(), v.end(),

BetweenValues(x, y));

...

}

// end of function

[1] To learn more about compose2, consult the SGI STL website (<http://www.sgi.com/tech/stl/>) or Matt Austern’s book, Generic Programming and the STL (Addison-Wesley, 1999).

[2] Range member functions are container member functions such as insert, erase, and assign that take two iterators specifying a range to e.g., insert, erase, or assign. A single call to a range member is generally much more efficient than a hand-written loop that does the same thing. For details, consult Item 5 of Effective STL.

0 0