事態的發展有時候總會趨向極端,這在那些惟美主義者當中猶是如此。首先聲明,我並非一個惟美主義者,提供第二版程序的改進版,徹底是爲了讓你更深入的感覺到STL的魅力所在。在看完第三版以後,你會強烈感覺到這一點。或許你也會變成一個惟美主義者了,至少在STL方面。這應該不是個人錯,由於決定權在你手裏。下面咱們來看看這個絕版的C++程序。c++
// name:example2_3.cpp // alias:aesthetic version #include <iostream> #include <vector> #include <algorithm> #include <iterator> using namespace std; void main(void) { typedef vector<int> int_vector; typedef istream_iterator<int> istream_itr; typedef ostream_iterator<int> ostream_itr; typedef back_insert_iterator< int_vector > back_ins_itr; // STL中的vector容器 int_vector num; // 從標準輸入設備讀入整數, // 直到輸入的是非整型數據爲止 copy(istream_itr(cin), istream_itr(), back_ins_itr(num)); // STL中的排序算法 sort(num.begin(), num.end()); // 將排序結果輸出到標準輸出設備 copy(num.begin(), num.end(), ostream_itr(cout, "\n")); }
在這個程序裏幾乎每行代碼都是和STL有關的(除了main和那對花括號,固然還有註釋),而且它包含了STL中幾乎全部的各大部件(容器container,迭代器iterator, 算法algorithm, 適配器adaptor),惟一的遺憾是少了函數對象(functor)的身影。web
還記得開頭提到的一個典型系統所具備的基本特徵嗎?--輸入+處理+輸出。全部這些功能,在上面的程序裏,僅僅是經過三行語句來實現的,其中每一行語句對應一種操做。對於數據的操做被高度的抽象化了,而算法和容器之間的組合,就像搭積木同樣輕鬆自如,系統的耦合度被降到了極低點。這就是閃耀着泛型之光的STL的偉大力量。如此簡潔,如此巧妙,如此神奇!就像魔術通常,以致於再一次讓你摸不着頭腦。怎麼實現的?爲何在看第二版程序的時候如此清晰的你,又墜入了五里霧中(竊喜)。算法
請留意此處的標題(惟美主義的傑做),在實際環境中,你未必要作到這樣完美。畢竟美好願望的破滅,在生活中時常會發生。過於理想化,並非一件好事,至少我是這麼認爲的。正如前面提到的,這個程序只是爲了展現STL的獨特魅力,你不得不爲它的出色表現所折服,也許只有深諳STL之道的人才會想出這樣的玩意兒來。若是你只是通常性的使用STL,作到第二版這樣的程度也就能夠了。數組
實在是由於這個程序太過"簡單",以致於我沒法確定,在你尚未徹底掌握STL以前,經過個人講解,是否可以領會這區區三行代碼,我將盡個人最大努力。函數
前面提到的迭代器能夠對容器內的任意元素進行定位和訪問。在STL裏,這種特性被加以推廣了。一個cin表明了來自輸入設備的一段數據流,從概念上講它對數據流的訪問功能相似於通常意義上的迭代器,可是C++中的cin在不少地方操做起來並不像是一個迭代器,緣由就在於其接口和迭代器的接口不一致(好比:不能對cin進行++運算,也不能對之進行取值運算--即*運算)。爲了解決這個矛盾,就須要引入適配器的概念。istream_iterator即是一個適配器,它將cin進行包裝,使之看起來像是一個普通的迭代器,這樣咱們就能夠將之做爲實參傳給一些算法了(好比這裏的copy算法)。由於算法只認得迭代器,而不會接受cin。對於上面程序中的第一個copy函數而言,其第一個參數展開後的形式是:istream_iterator(cin),其第二個參數展開後的形式是:istream_iterator()(若是你對typedef的語法不清楚,能夠參考有關的c++語言書籍)。其效果是產生兩個迭代器的臨時對象,前一個指向整型輸入數據流的開始,後一個則指向"pass-the-end value"。這個函數的做用就是將整型輸入數據流從頭到尾逐一"拷貝"到vector這個準整型數組裏,第一個迭代器從開始位置每次累進,最後到達第二個迭代器所指向的位置。或許你要問,若是那個copy函數的行爲真如我所說的那樣,爲何不寫成以下這個樣子呢?組件化
copy(istream_iterator<int>(cin), istream_iterator<int>(), num.begin()); 你確實能夠這麼作,可是有一個小小的麻煩。還記得初版程序裏的那個數組越界問題嗎?若是你這麼寫的話,就會遇到相似的麻煩。緣由在於copy函數在"拷貝"數據的時候,若是輸入的數據個數超過了vector容器的範圍時,數據將會拷貝到容器的外面。此時,容器不會自動增加容量,由於這只是簡單地拷貝,並非從末端插入。爲了解決這個問題,另外一個適配器back_insert_iterator登場了,它的做用就是引導copy算法每次在容器末端插入一個數據。程序中的那個back_ins_itr(num)展開後就是:back_insert_iterator
終於將講完了三分之一(真不容易!),好在第二句和前一版程序沒有差異,這裏就略過了。至於第三句,ostream_itr(cout, "\n")展開後的形式是:ostream_iterator(cout, "\n"),其效果是產生一個處理輸出數據流的迭待器對象,其位置指向數據流的起始處,而且以"\n"做爲分割符。第二個copy函數將會從頭到尾將vector中的內容"拷貝"到輸出設備,第一個參數所表明的迭代器將會從開始位置每次累進,最後到達第二個參數所表明的迭代器所指向的位置。spa
這就是所有的內容。code
歷史的車輪老是滾滾向前的,工業時代的文明較之史前時代,固然是先進而且發達的。回顧那兩個時代的C++程序,你會真切的感覺到這種差異。簡潔易用,具備工業強度,較好的可移植性,高效率,加之第三個使人目眩的絕版程序所體現出來的高度抽象性,高度靈活性和組件化特性,使你對STL背後所蘊含的泛型化思想都有了些微的感覺。
真幸運,你能夠橫跨兩個時代,有機會目擊這種"文明"的差別。同時,這也應該使你越加堅決信念,使本身順應時代的潮流。
事態的發展有時候總會趨向極端,這在那些惟美主義者當中猶是如此。首先聲明,我並非一個惟美主義者,提供第二版程序的改進版,徹底是爲了讓你更深入的感覺到STL的魅力所在。在看完第三版以後,你會強烈感覺到這一點。或許你也會變成一個惟美主義者了,至少在STL方面。這應該不是個人錯,由於決定權在你手裏。下面咱們來看看這個絕版的C++程序。
// name:example2_3.cpp // alias:aesthetic version #include <iostream> #include <vector> #include <algorithm> #include <iterator> using namespace std; void main(void) { typedef vector<int> int_vector; typedef istream_iterator<int> istream_itr; typedef ostream_iterator<int> ostream_itr; typedef back_insert_iterator< int_vector > back_ins_itr; // STL中的vector容器 int_vector num; // 從標準輸入設備讀入整數, // 直到輸入的是非整型數據爲止 copy(istream_itr(cin), istream_itr(), back_ins_itr(num)); // STL中的排序算法 sort(num.begin(), num.end()); // 將排序結果輸出到標準輸出設備 copy(num.begin(), num.end(), ostream_itr(cout, "\n")); }
在這個程序裏幾乎每行代碼都是和STL有關的(除了main和那對花括號,固然還有註釋),而且它包含了STL中幾乎全部的各大部件(容器container,迭代器iterator, 算法algorithm, 適配器adaptor),惟一的遺憾是少了函數對象(functor)的身影。
還記得開頭提到的一個典型系統所具備的基本特徵嗎?--輸入+處理+輸出。全部這些功能,在上面的程序裏,僅僅是經過三行語句來實現的,其中每一行語句對應一種操做。對於數據的操做被高度的抽象化了,而算法和容器之間的組合,就像搭積木同樣輕鬆自如,系統的耦合度被降到了極低點。這就是閃耀着泛型之光的STL的偉大力量。如此簡潔,如此巧妙,如此神奇!就像魔術通常,以致於再一次讓你摸不着頭腦。怎麼實現的?爲何在看第二版程序的時候如此清晰的你,又墜入了五里霧中(竊喜)。
請留意此處的標題(惟美主義的傑做),在實際環境中,你未必要作到這樣完美。畢竟美好願望的破滅,在生活中時常會發生。過於理想化,並非一件好事,至少我是這麼認爲的。正如前面提到的,這個程序只是爲了展現STL的獨特魅力,你不得不爲它的出色表現所折服,也許只有深諳STL之道的人才會想出這樣的玩意兒來。若是你只是通常性的使用STL,作到第二版這樣的程度也就能夠了。
實在是由於這個程序太過"簡單",以致於我沒法確定,在你尚未徹底掌握STL以前,經過個人講解,是否可以領會這區區三行代碼,我將盡個人最大努力。
前面提到的迭代器能夠對容器內的任意元素進行定位和訪問。在STL裏,這種特性被加以推廣了。一個cin表明了來自輸入設備的一段數據流,從概念上講它對數據流的訪問功能相似於通常意義上的迭代器,可是C++中的cin在不少地方操做起來並不像是一個迭代器,緣由就在於其接口和迭代器的接口不一致(好比:不能對cin進行++運算,也不能對之進行取值運算--即*運算)。爲了解決這個矛盾,就須要引入適配器的概念。istream_iterator即是一個適配器,它將cin進行包裝,使之看起來像是一個普通的迭代器,這樣咱們就能夠將之做爲實參傳給一些算法了(好比這裏的copy算法)。由於算法只認得迭代器,而不會接受cin。對於上面程序中的第一個copy函數而言,其第一個參數展開後的形式是:istream_iterator(cin),其第二個參數展開後的形式是:istream_iterator()(若是你對typedef的語法不清楚,能夠參考有關的c++語言書籍)。其效果是產生兩個迭代器的臨時對象,前一個指向整型輸入數據流的開始,後一個則指向"pass-the-end value"。這個函數的做用就是將整型輸入數據流從頭到尾逐一"拷貝"到vector這個準整型數組裏,第一個迭代器從開始位置每次累進,最後到達第二個迭代器所指向的位置。或許你要問,若是那個copy函數的行爲真如我所說的那樣,爲何不寫成以下這個樣子呢?
copy(istream_iterator<int>(cin), istream_iterator<int>(), num.begin()); 你確實能夠這麼作,可是有一個小小的麻煩。還記得初版程序裏的那個數組越界問題嗎?若是你這麼寫的話,就會遇到相似的麻煩。緣由在於copy函數在"拷貝"數據的時候,若是輸入的數據個數超過了vector容器的範圍時,數據將會拷貝到容器的外面。此時,容器不會自動增加容量,由於這只是簡單地拷貝,並非從末端插入。爲了解決這個問題,另外一個適配器back_insert_iterator登場了,它的做用就是引導copy算法每次在容器末端插入一個數據。程序中的那個back_ins_itr(num)展開後就是:back_insert_iterator
終於將講完了三分之一(真不容易!),好在第二句和前一版程序沒有差異,這裏就略過了。至於第三句,ostream_itr(cout, "\n")展開後的形式是:ostream_iterator(cout, "\n"),其效果是產生一個處理輸出數據流的迭待器對象,其位置指向數據流的起始處,而且以"\n"做爲分割符。第二個copy函數將會從頭到尾將vector中的內容"拷貝"到輸出設備,第一個參數所表明的迭代器將會從開始位置每次累進,最後到達第二個參數所表明的迭代器所指向的位置。
這就是所有的內容。
歷史的車輪老是滾滾向前的,工業時代的文明較之史前時代,固然是先進而且發達的。回顧那兩個時代的C++程序,你會真切的感覺到這種差異。簡潔易用,具備工業強度,較好的可移植性,高效率,加之第三個使人目眩的絕版程序所體現出來的高度抽象性,高度靈活性和組件化特性,使你對STL背後所蘊含的泛型化思想都有了些微的感覺。
真幸運,你能夠橫跨兩個時代,有機會目擊這種"文明"的差別。同時,這也應該使你越加堅決信念,使本身順應時代的潮流。