Effective_STL 學習筆記(四十三) 盡量用算法調用代替手寫循環
每一個算法接受至少一對用來指示將被操作對象區間的叠代器,比如,min_element 可以找出此區間中的最小的值,而 accumulate 則對區間內的元素作某種形式的整體求和運算,partition 將區間內的元素分割為滿足和不滿足某某判決條件的兩個部分。算法執行時,他們進行檢查指示給它的區間中的每一個元素,並且按照所期望的方式進行: 從區間中的起點循環到結束點。有一些算法,比如 find 和 find_if,可能在遍歷完成前就返回了,但是即使是這些算法,內部都包含一個循環。
算法內部是一個循環,STL 的廣泛涉及面意味著,很多要用循環實現的任務,可以改用算法實現。
1 classWidget 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));
把叠代器扔給算法,讓他們考慮操縱叠代器時的各種詭異
Effective_STL 學習筆記(四十三) 盡量用算法調用代替手寫循環