43.算法調用優先於手寫的循環。
算法的內部是循環,更進一步,由於STL算法涉及面很廣,所以本該編寫循環來完成的任務也可以用STL算法完成。
一個非常典型的例子:
如果有一個Widget類:
class Widget
{
public:
void redraw() const;
};
當需要調用每個Widget的redraw函數時,可以這樣:
vector<Widget> v;
for(vector<Widget>::iterator it = v.begin(); it != v.end();++it)
it->redraw();
也可以選擇用for_each算法:
vector<Widget> v;
for_each(v.begin(),v.end(),mem_fun_ref(&Widget::redraw));
推薦採用算法的方式。
有三個原因:
1.效率:算法通常比程序員自己寫的循環效率更高。
2.正確性:自己寫循環比使用算法更容易出錯。
3.可維護性:使用算法的代碼通常比手寫循環的代碼更加簡潔明瞭。
但是如果想表明在一次迭代中該完成什麼工作,使用循環比使用算法更爲清晰。比如說要確定一個容器中第一個大於x,小於y的元素,使用循環可以這樣實現:
vector<int> v;
int x,y;
……
vector<int>::iterator it = v.begin();
for(; it != v.end(); ++it)
{
if(*it > x && *it < y)
break;
}
當然也可以定義一個仿函數:
class BetweenValue
{
private:
int lowVal;
int hignVal;
public:
BetweenValue(int low = int(),int high = int()):lowVal(low),hignVal(high){}
bool operator()(int val) const
{
return val > lowVal && val < hignVal;
}
};
這裏書上說的貌似有點問題,書上說,如果在函數裏調用創建的仿函數會出現問題。如果仿函數定義成模板,則根本不能通過編譯,如果設計成類而不是模板的話,也是有問題。因爲在函數內部聲明的類是局部類,而局部類不能作爲模板的類型實參(如find_if所需要的仿函數類型)。
而事實上是可以的,如下面的代碼:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <iterator>
using namespace std;
class BetweenValue
{
private:
int lowVal;
int hignVal;
public:
BetweenValue(int low = int(),int high = int()):lowVal(low),hignVal(high){}
bool operator()(int val) const
{
return val > lowVal && val < hignVal;
}
};
void FindFirst(const vector<int> &ivec,int x,int y)
{
vector<int>::const_iterator it = find_if(ivec.begin(),ivec.end(),BetweenValue(x,y));
cout << *it << endl;
}
int main()
{
vector<int> ivec;
for(int i = 9; i <= 14; ++i)
ivec.push_back(i);
FindFirst(ivec,10,20);
return 0;
}
唯一要注意的是:當函數的形參是const類型的容器時,使用容器的迭代器務必要使用const_iterator類型。
44.容器的成員函數優先於同名的算法。
1.成員函數往往速度快。
2.c成員函數通常與容器(特別是關聯容器)結合得更加緊密,這是算法所不能比的。
45.正確區分count,find,binary_search,lower_bound,upper_bound和equal_range。
對於未排序的區間,判斷是否存在給定值,用find。對於已經排序的區間,用binary_search。
對於排序區間,如果要找給定值在哪裏,equal_range不僅完成了find的工作,同時也代替了count。
結論如下表所示:
46.考慮使用函數對象而不是函數作爲STL算法的參數。
原因很簡單,使用仿函數效率更高。
47.避免產生“直寫型”(write-only)的代碼。
將複雜語句分解成易於理解的簡單語句,並且加上一些註釋。
48.總是包含正確的頭文件。
1.幾乎所有的標準STL容器都被聲明在與之同名的頭文件中。
2.除了4個STL算法以外,其他所有的算法都被聲明在<algorithm>中,這4個算法是accumulate,inner_product,adjacent_difference和partial_sum。這4個被聲明在<numeric>中。
3.特殊類型的迭代器,包括istream_iterator等,被聲明在<iterator>中。
4.預定義的仿函數以及配接器,被聲明在<functional>中。
49.學會分析與STL相關的編譯器診斷信息。
50.熟悉與STL相關的Web站點。