16.算法调用优先于手写的循环
STL算法涉及面很廣,這意味著你本該編寫循環來完成的任務也可以用STL算法來完成。
例如,有一個Widget類:
class Widget { public:...void redraw() const;... };當你想在一個包含Widget的list中調用所有成員的Widget對象,可以用一個循環來完成,
std::list<Widget> datas; ... for (auto iter = datas.begin(); ?iter != datas.end(); ++iter) {iter->redraw(); }你也可以選擇使用for_each算法來完成:
for_each(datas.begin(), datas.end(), mem_fun_ref(Widget::redraw));編寫一個循環比調用一個算法更在簡單,但事實上調用算法通常是更好的選擇,它往往優先于任何一個手寫循環。理由有三:
- 效率:算法通常比自己學的循環效率更高。
- 正確性:手學循環比使用算法更容器出錯。
- 可維護性:使用算法的代碼通常比手寫循環的更加簡潔明了。
從效率看:
使用算法可以減少冗余的計算。
對于循環:
for (auto iter = datas.begin(); iter != datas.end(); ++iter) {iter->redraw(); }每一次循環的額時候,list::end()都要被調用。但是并不需要多次調用它,因為并沒有改變list。
如果使用算法:
std::for_each(datas.begin(), datas.end(), mem_fun_ref(&Widget::redraw()));STL的實現者很清楚,begin、end都是被頻繁調用的函數,所以他們盡可能提高其效率,幾乎可以肯定會使用inline來編譯這些函數,并且努力改善這些函數的代碼,盡可能讓大多數編譯器都能夠將循環中的計算提到外面來,避免重復計算。
類庫實現者可以根據他們對容器實現的了解程度對遍歷過程進行優化,這是庫的使用者難以做到的。無論如何實現者肯定比調用者更了解內部的實現細節,他們可以在算法實現中充分利用這些知識。如果你避開算法使用自己的手寫循環,你也就放棄了這些算法實現者可能提供的優化手段。
除了一些不太重要的算法之外,其他幾乎所有的算法都使用了復雜的計算機科學算法,有些非常復雜,并非一般的程序員所能夠達到。
從正確性看:
當你編寫循環代碼的時候,最緊要的莫過于與要保證你所使用的迭代器都是有效的,并且指向你所希望的地方。
從清晰度看:
最好的代碼時最簡潔、可讀性最好的軟件,是最容器擴展功能、最容易維護和適用于新環境的軟件,盡管我們對循環更為熟悉,但是從長遠上看,算法更具競爭力。
當你看到for、while或do的時候,你所知道的只不過是某一種循環將要出現。要想知道這個循環的用途,哪怕時最初略的用途,你都必須檢查具體的代碼。但是,當你看到了一個算法調用的時候,它的名稱就會指出它的用途。當然,如果你想知道它到底做了什么,你必須檢查哪些傳給算法的實參的意義,但這通常比看懂一個循環結果的意圖要簡單得多。
在算法調用與手寫循環中的斗爭中,關于代碼清晰度的底線最終取決于你要在循環中做什么事情。如果你要做的工作與一個算法所實現的功能很相近,那么用算法調用更好。如果你的循環很簡單,若使用算法來實現的話,卻要求混合使用綁定器或者一個單獨的函數子類,那么,手寫循環可能更好。最后,如果你在循環中要做的事情很多,而且很復雜,則最好使用算法調用,因為冗長又復雜的計算任務總是應該被放到單獨的函數中。而一旦你把循環體移動到單獨的函數中,你總是可以找到一個函數傳給算法(例如for_each),這樣得到的代碼有直接、又清楚。
使用STL的精巧的C++程序比不用STL的程序所包含的循環要少得多,這是一件好事。任何時候我們都應該盡量用較高層次的insert、find和for_each來替換較低層次的for、while和do。因為這樣可以提高軟件的抽象層次,從而使軟件更易于編寫,更易于文檔化,也更易于擴展和維護。
總結
以上是生活随笔為你收集整理的16.算法调用优先于手写的循环的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 15.确保“lessT“与“operat
- 下一篇: 17.容器的成员函数优先于同名的算法