作為C++標准不可缺少的一部分,STL應該是滲透在C++程序的角角落落裡的。STL不是實驗室裡的寵兒,也不是程序員桌上的擺設,她的激動人心並非昙花一現。本教程旨在傳播和普及STL的基礎知識,若能借此機會為STL的推廣做些力所能及的事情,到也是件讓人愉快的事情。
初識STL:解答一些疑問
1.1 一個最關心的問題:什麼是STL
"什麼是STL?",假如你對STL還知之甚少,那麼我想,你一定很想知道這個問題的答案,坦率地講,要指望用短短數言將這個問題闡述清楚,也決非易事。因此,如果你在看完本節之後還是覺得似懂非懂,大可不必著急,在閱讀了後續內容之後,相信你對STL的認識,將會愈加清晰、准確和完整。不過,上述這番話聽起來是否有點像是在為自己糟糕的表達能力開脫罪責呢?:)
不知道你是否有過這樣的經歷。在你准備著手完成數據結構老師所布置的家庭作業時,或者在你為你所負責的某個軟件項目中添加一項新功能時,你發現需要用到一個鏈表(List)或者是映射表(Map)之類的東西,但是手頭並沒有現成的代碼。於是在你開始正式考慮程序功能之前,手工實現List或者Map是不可避免的。於是……,最終你順利完成了任務。或許此時,作為一個具有較高素養的程序員的你還不肯罷休(或者是一個喜歡偷懶的優等生:),因為你會想到,如果以後還遇到這樣的情況怎麼辦?沒有必要再做一遍同樣的事情吧!
如果說上述這種情形每天都在發生,或許有點誇張。但是,如果說整個軟件領域裡,數十年來確實都在為了一個目標而奮斗--可復用性(reusability),這看起來似乎並不誇張。從最早的面向過程的函數庫,到面向對象的程序設計思想,到各種組件技術(如:COM、EJB),到設計模式(design pattern)等等。而STL也在做著類似的事情,同時在它背後蘊涵著一種新的程序設計思想--泛型化設計(generic programming)。
繼續上面提到的那個例子,假如你把List或者map完好的保留了下來,正在暗自得意。且慢,如果下一回的List裡放的不是浮點數而是整數呢?如果你所實現的Map在效率上總是令你不太滿意並且有時還會出些bug呢?你該如何面對這些問題?使用STL是一個不錯的選擇,確實如此,STL可以漂亮地解決上面提到的這些問題,盡管你還可以尋求其他方法。
說了半天,到底STL是什麼東西呢?
STL(Standard Template Library),即標准模板庫,是一個具有工業強度的,高效的C++程序庫。它被容納於C++標准程序庫(C++ Standard Library)中,是ANSI/ISO C++標准中最新的也是極具革命性的一部分。該庫包含了諸多在計算機科學領域裡所常用的基本數據結構和基本算法。為廣大C++程序員們提供了一個可擴展的應用框架,高度體現了軟件的可復用性。這種現象有些類似於Microsoft Visual C++中的MFC(Microsoft Foundation Class Library),或者是Borland C++ Builder中的VCL(Visual Component Library),對於此二者,大家一定不會陌生吧。
從邏輯層次來看,在STL中體現了泛型化程序設計的思想(generic programming),引入了諸多新的名詞,比如像需求(requirements),概念(concept),模型(model),容器(container),算法(algorithmn),迭代子(iterator)等。與OOP(object-oriented programming)中的多態(polymorphism)一樣,泛型也是一種軟件的復用技術。
從實現層次看,整個STL是以一種類型參數化(type parameterized)的方式實現的,這種方式基於一個在早先C++標准中沒有出現的語言特性--模板(template)。如果查閱任何一個版本的STL源代碼,你就會發現,模板作為構成整個STL的基石是一件千真萬確的事情。除此之外,還有許多C++的新特性為STL的實現提供了方便。
不知你對這裡一下子冒出這麼多術語做何感想,希望不會另你不愉快。假如你對它們之中的大多數不甚了解,敬請放心,在後續內容中將會對這些名詞逐一論述。正如開頭所提到的。
有趣的是,對於STL還有另外一種解釋--STepanov & Lee,前者是指Alexander Stepanov,STL的創始人;而後者是Meng Lee,她也是使STL得以推行的功臣,第一個STL成品就是他們合作完成的。這一提法源自1995年3月,Dr.Dobb’s Journal特約記者, 著名技術書籍作家Al Stevens對Alexander Stepanov的一篇專訪。
1.2 追根溯源:STL的歷史
在結識新朋友的時候,大多數人總是忍不住想了解對方的過去。本節將帶您簡單回顧一下STL的過去。
被譽為STL之父的Alexander Stepanov,出生於蘇聯莫斯科,早在20世紀70年代後半期,他便已經開始考慮,在保證效率的前提下,將算法從諸多具體應用之中抽象出來的可能性,這便是後來泛型化思想的雛形。為了驗證自己的思想,他和紐約州立大學教授Deepak Kapur,倫塞裡爾技術學院教授David Musser共同開發了一種叫做Tecton的語言。盡管這次嘗試最終沒有取得實用性的成果,但卻給了Stepanov很大的啟示。
在隨後的幾年中,他又和David Musser等人先後用Schema語言(一種Lisp語言的變種)和Ada語言建立了一些大型程序庫。這其間,Alexander Stepanov開始意識到,在當時的面向對象程序設計思想中所存在的一些問題,比如抽象數據類型概念所存在的缺陷。Stepanov希望通過對軟件領域中各組成部分的分類,逐漸形成一種軟件設計的概念性框架。
1987年左右,在貝爾實驗室工作的Alexander Stepanov開始首次采用C++語言進行泛型軟件庫的研究。但遺憾的是,當時的C++語言還沒有引入模板(template)的語法,現在我們可以清楚的看到,模板概念之於STL實現,是何等重要。是時使然,采用繼承機制是別無選擇的。盡管如此,Stepanov還是開發出了一個龐大的算法庫。與此同時,在與Andrew Koenig(前ISO C++標准化委員會主席)和Bjarne Stroustrup(C++語言的創始人)等頂級大師們的共事過程中,Stepanov開始注意到C/C++語言在實現其泛型思想方面所具有的潛在優勢。就拿C/C++中的指針而言,它的靈活與高效運用,使後來的STL在實現泛型化的同時更是保持了高效率。另外,在STL中占據極其重要地位的迭代子概念便是源自於C/C++中原生指針( native pointer)的抽象。
1988年,Alexander Stepanov開始進入惠普的Palo Alto實驗室工作,在隨後的4年中,他從事的是有關磁盤驅動器方面的工作。直到1992年,由於參加並主持了實驗室主任Bill Worley所建立的一個有關算法的研究項目,才使他重新回到了泛型化算法的研究工作上來。項目自建立之後,參與者從最初的8人逐漸減少,最後只剩下兩個人--Stepanove本人和Meng Lee。經過長時間的努力,最終,信念與汗水所換來的是一個包含有大量數據結構和算法部件的龐大運行庫。這便是現在的STL的雛形(同時也是STL的一個實現版本--HP STL)。
1993年,當時在貝爾實驗室的Andrew Koenig看到了Stepanove的研究成果,很是興奮。在他的鼓勵與幫助下,Stepanove於是年9月的聖何塞為ANSI/ISO C++標准委員會做了一個相關演講(題為"The Science of C++ Programming"),向委員們講述了其觀念。然後又於次年3月,在聖迭戈會議上,向委員會提交了一份建議書,以期使STL成為C++標准庫的一部分。盡管這一建議十分龐大,以至於降低了被通過的可能性,但由於其所包含的新思想,投票結果以壓倒多數的意見認為推遲對該建議的決定。
隨後,在眾人的幫助之下,包括Bjarne Stroustrup在內,Stepanove又對STL進行了改進。同時加入了一個封裝內存模式信息的抽象模塊,也就是現在STL中的allocator,它使STL的大部分實現都可以獨立於具體的內存模式,從而獨立於具體平台。在同年夏季的滑鐵盧會議上,委員們以80%贊成,20%反對,最終通過了提案,決定將STL正式納入C++標准化進程之中,隨後STL便被放進了會議的工作文件中。自此,STL終於成為了C++家族中的重要一員。
此後,隨著C++標准的不斷改進,STL也在不斷地作著相應的演化。直至1998年,ANSI/ISO C++標准正式定案,STL始終是C++標准中不可或缺的一大部件。
1.3 千絲萬縷的聯系
在你了解了STL的過去之後,一些名詞開始不斷在你的大腦中浮現,STL、C++、C++標准函數庫、泛型程序設計、面向對象程序設計……,這些概念意味著什麼?他們之間的關系又是什麼?如果你想了解某些細節,這裡也許有你希望得到的答案。
1.3.1 STL和C++
沒有C++語言就沒有STL,這麼說毫不為過。一般而言,STL作為一個泛型化的數據結構和算法庫,並不牽涉具體語言(當然,在C++裡,它被稱為STL)。也就是說,如果條件允許,用其他語言也可以實現之。這裡所說的條件,主要是指類似於"模板"這樣的語法機制。如果你沒有略過前一節內容的話,應該可以看到,Alexander Stepanov在選擇C++語言作為實現工具之前,早以采用過多種程序設計語言。但是,為什麼最終還是C++幸運的承擔了這個歷史性任務呢?原因不僅在於前述那個條件,還在於C++在某些方面所表現出來的優越特性,比如:高效而靈活的指針