如何学习STL

其实STL并不是很难学. 如果你不太愿意购买大部头著作阅读, 那么, "Essential xxx",  
"xxx in a Nutshell"之类简明扼要的文章书籍就很有帮助了. 我在CSDN文档区看到一篇 
Using STL的译文, Kary翻译, 很简短, 用于了解STL基本概念挺合适的. 侯捷先生也写了 
STL系列文章 (请到 http://jjhou.csdn.net 使用浏览器在左部页面搜索"STL"字样) ,  
从入门到提高均有. 看过之后, 你心中应对STL有了个大概了. 再使用随你的编译器提供 
的STL Reference Manual了解一下STL中都有哪些containers, 每个container都提供了 
哪些操作, STL中还有些什么algorithms, 各自都做些什么事情, 那么你基本上就可以用 
STL来编程了. 可能会在编程中遇到一些问题, 比如container扩大之后iterator怎么失 
效了... 一回生两回熟, 几次下来也就解决了. 在解决问题的过程中你可能会需要跟踪 
STL的源代码, 那么经几次在源码中的沉浮后, 对于STL的实作也就有了相当知识了. 
  
网上也有不少STL Tutorials, 较好的资料一是在SGI站点上, 前文访谈录中已给出URL.  
另一在dinkumware站点 ( http://www.dinkumware.com )上. Dinkumware STL 及其 
Reference Manual都是P. J. Plauger的作品. Plauger也是下文要推荐的 
The C++ Template Library一书的第一作者. C++编译器的两大流派 BCB 和 VC  
分别采用 基于 SGI STL 的 STLport 和 dinkumware STL . 这意味着, 如果你使用的 
编译器是BCB或VC(应该大多数人如此吧?), 那就不必上网看了. 直接离线浏览帮助文件 
吧. BCB的STL帮助文档也附带介绍了一些网络上的STL资源和STL相关书籍, 读者可以参考. 
  
通过这些资源学习STL有个缺点是显得有点零敲碎打, 不够系统化. 那么一本好的书籍就 
非常有益了. 喜欢看书的读者可赶上好时候了, 近来会有不少STL的经典之作引入国内.  
其中有好几本侯捷先生的译作和著作, 但抢了先机的还是前面访谈录译注中提到的 
The C++ Standard Template Library一书, 由Plauger, Stepanov等四大高手联手推出.  
cber翻译, 中译本由电力出版社出版. 在国外的STL经典之作中, 这本书出得最晚,  
但引入国内却是最早的. 下面我分应用和实作两个层面来推荐STL经典书籍. 
  
实作比应用高阶, 我就"柿子先挑硬的捏", 先说实作层面吧. 要分析STL实作, 看编译器 
自带的源代码当然是一个方法, 但吃力不讨好. 代码中遍布大写字母构成的宏和前缀下 
划线, 真是"乱花渐欲迷人眼". 侯捷先生整理了一份SGI STL的源码, 中文彩色注释,  
在他的站点上可以找到. 非常感谢! 这份代码还是比较清晰的, 但这也不足以让你毫无 
痛苦地学习STL实作. 多付几十元钱买本结构清晰而带有适当讲解的书可以节省大量自己 
摸索所需的时间和精力, 让你事半功倍. The C++ Standard Template Library就是这样 
的书: 言简意赅, 层次分明, 学查皆宜. 不过这本书并不是人人能读懂的. 如果你的程 
度还不够, 需要多花些时间并且喜欢一个良师循循善诱地教你的风格, 那我推荐侯捷的 
《STL源码剖析》. 前面提到的SGI STL源码就是侯捷先生写作该书整理的. 我并不是说 
这本书比前者浅显, 而是讲得比前者讲得细致. 
  
《STL源码剖析》写得深入浅出, 讲得非常详细, 有很多图, 行文生动活泼, 一如侯捷 
既往的风格. 但像insert(pos, elem)这样的函数之语义也要几幅图来阐述(图真的很精 
美!), 未免有点冗长了. 本书很适合初学者和一般程度的读者用来学习STL之实作, 但 
可能急性子的高手会不耐烦. 而且本书结构和组织性也只适合学不适合查. 就这点而言,  
The C++ Standard Template Library做得更好: 至少它列出了完整的, 经"可读性"优化 
的源代码和STL各组件的编程界面, 覆盖了运用和实作两个层面. 估计初学者会比较偏爱 
《STL源码剖析》, 因为这本书前面还列出了阅读STL所需的C++预备知识, 真是对读者照 
顾得无微不至. 但如果你水平到了一定程度, 又是急性子, 而且想要一本"附带了实作分 
析的参考手册", 还是用The C++ Standard Template Library吧. 
  
另外, 说件有趣的事情: 我阅读《STL源码剖析》时注意到一个细节, 侯捷先生在 
SGI STL实作某处加了注释: 实作中对于不支持"typename"关键字的编译器, 将 
"typename"一词用#define语句定义为空, 而侯先生在旁注释"为何不 
#define typename class?". 我碰巧在读该书之前不解: 既然现代编译器大多支持"更 
为现代"的typename 关键字, 为何STL实作中大量可见的还是template <class T> 而非  
template <typename T>? 当时只是存疑, 没有细究. 后来又看到孟岩先生的文章, 阐述 
了typename的"另一种用法"--显式地告诉编译器"此token为typename是也, 而非 
variable name或function name". 我读《STL源码剖析》时联想到这些, 立时有恍然之 
感. 这经历说明了广泛阅读相互比照的好处. 一个猜想是否正确? 多看几本书看几篇文 
章吧. STL的大师之作有好几本, 难以取舍, 那么如果可以承受的话, 不妨都买下来吧.  
作者是人, 人非圣贤, 孰能面面俱到而无过也? 更何况还有"无错不成书"的说法. (The  
C++ Standard Template Library 一书中就有几个错误. 作者已经犯下了, 译者也未改 
正. 详见ACCU.org上该书书评. ) 也许几本书对照着看才能多悟出点东西来. 
  
再回过来来说The C++ Standard Template Library一书. 这本书比较新, 除了讲STL的 
界面, 运用; 还讲了其实作. 很实用, 结构也很清晰. 你可以把它当教材, 也可以当参 
考手册. 在ACCU.org上面有资深读者对该书评价不高(哦, 岂止不高, 简直是评价很低),  
大意是可以用其它资料替代书中的内容, 另外书中有"硬伤", 讲解也不够详细. 我却不 
以为然. 确实, 本书中资料大多可用其它资料替代(相比之下《STL源码剖析》中侯捷先 
生深入浅出的剖析, 大量精美的插图和循循善诱的解说, 倒是无可替代的--至少目前来 
看如此. ^_^ ), 我在前文中也给出了一些替代性的网络资源, 如dinkumware站点(其实 
Plauger写作该书时也引用了不少Dinkumware STL Reference的内容). 但为何要买书啊,  
就是要省时间, 省眼力(除非你的显示器是液晶的). 所以此"可替代性"论点不成立. 至 
于"讲解不够详细"之批判, 本书"实作解析"部分确实不详细, 连图都没有. 但我觉得这 
样的讲解言简意赅, 省了我大量的阅读时间啊, 而且我也学到了我想学的东西, 这种方 
式, 我喜欢. 内容讲至何种程度为佳(指展开程度, 而非深入程度), 这实属萝卜青菜各 
有所爱了. 自然, 要看明白本书需要相当C++背景知识. 或许有些人更喜欢娓娓道来的方 
式. 那么还是看侯捷的《STL源码剖析》吧. 至于说本书中之"硬伤", 并不是太多, 而且 
事关exception safety, 估计不少读者根本就不会注意. 无错不成书, 还是宽容一点吧.  
STL之父犯下的"错误", 你要是同样犯, 也无太多可指责之处了. 说到这里, 我又想强 
调了: 也许几本书对照着看倒能多点收益. 
  
"硬柿子"捏的差不多了, 我再来说说比较简单的运用层面吧. 这个层面的书就比较多了 
(呵呵, 情况永远如此--想想金字塔底面和塔尖的比例). 其中 The C++ Standard  
Template Library, A Tutorial and Reference 一书当属经典. 这本书面面俱到,  
不仅在运用层面称霸, 还涉及到了STL实作层面. STL好书不少, 侯捷先生曾在几篇文章 
中全面涉及并评论, 见 http://jjhou.csdn.net , 此处不多重复了. 另外还有不少讲 
C++的书都讲到了STL. 除了侯先生在他的文章中提到的C++ Primer 3/e,  
The C++ Programming Language 3/e等书, 我再补充一本: Thinking in C++ 2e的第2卷 
中包括了使用STL所需要的知识, 其中Part 1 : The Standard C++ Library总共占300多 
页, 介绍了Strings, IOStreams, Templates in Depth, STL Containers and  
Iterators, STL Algorithms这些内容, 对于掌握和运用STL是足够了. 鉴于STL在标准 
C++中的重要地位, 讲C++的书自然不敢对其视而不见. 不过这些书中的STL内容一般是只 
够入门, 到运用层面为止. 也算聊胜于无吧. 你如果想要达到熟练高效运用STL之程度,  
那还远远不够.  
  
另外还要指出的是, STL只是一个Library, 而非Application Framework. 所以你可以将 
之和别的Application Framework一起使用, 这并不会产生不可调和的冲突. 不过始终要 
记住, 你用这个Library的目的是要给自己带来方便, 节省时间. 如果为了让两个 
Library或一个Library一个Application Framework顺利磨合在一起需要付出大量心力,  
那还不如不用呢. (而如果要让两个Application Framework, 例如MFC和VCL, 在一起顺 
利工作, 那可真是一件高难度的工作--除非因为转换平台需要复用以前大量代码, 否则 
完全得不偿失. ) 如果你只是运用STL中的string, vector等最基本的container(s)和 
near container(s), 一般总是很保险的, 不会出什么乱子. 比较深入的运用可能就会带 
来冲突了. 在出现冲突的情况下, 要么回避, 要么解决. 如果你对STL和那个 
Application Framework都有深入了解, 解决是有可能的, 而且过程中会学到不少东西.  
  
举个例子, 我曾编过一个人工生命模拟程序, 每个生命都作为VCL的TThread的一个实例 
而独立运行, 开始时我用一个vector<TLife>(TLife派生自TThread)来放置这些"生命",  
但很快发现不可行. 我的程序始终无法通过编译, 编译器给出的讯息是TLife类的对象无 
法构造.(为VCL类(及其派生类)的所有实例都不允许在栈上构造而必须在堆中构造). 怎 
么办那? 改呗, 改成vector<TLife*>, 不行; 再将TLife<-TThread的派生关系改成了 
TLife拥有TLifeThread, 而TLifeThread继承自TThread(没办法, 必须要用继承, 否则 
TThread的虚方法Execute()无从重定义), 然后让TLifeThread在TLife的constructor中 
从堆上分配, 在destructor中释放. 这带来了不少麻烦, 很多原本清晰的接口不得不重 
新设计. 有没有更好的解决方法? 我本来用vector的想法很单纯, 因为如果需要的话 
vector可以很容易替换成list等具有不同操作时间复杂性的容器; 而且在标准容器之上 
通过iterator施行for_each操作来对"生态系统"中的每个"生命"做某种相同行为可以让 
代码很直观. 但看来这一点点简单性要我付出的代价太大, 那么, 解决方案就很简单了:  
别用vector呗. 如果一样东西带来的麻烦超过了带来的好处, 那么就不要用它. 
  
在这个实例中, 相互作用的Library和Application Framework分别是STL和VCL. VCL自己 
的资源管理机制是完全运作在堆上的, 那处处传递的TOwner对象便是蛛丝马迹; 而 
vector以及STL中所有其它容器都很注重"栈"的应用, 甚至依靠"栈"来进行资源管理,  
达到"准GC"的功效. 这和VCL是背道而驰的. 两者不同之处还有很多, 比如最基本的, 连 
代码风格也是不同的. 当你想"脚踏两只船"时, 这些都不得不细细权衡. 
  
再举STL中function objects的例子. 在这样的语句  
for_each(v.begin(), v.end(), some_op); 中some_op是一个function object, 这种用 
法在纯粹的使用Generic Programming Paradigm编写的程序中确实很方便, 但在 
OO Paradigm中some_op在何处定义却成了问题, some_op传递给v的参数必须要事先封装 
在function object中, 而这个参数很可能碰巧是某个类的私有数据. 将some_op定义为 
全局的struct? 还是嵌套在该私有数据所在的类中? 要将function object的定义声明为 
该类的友元吗? 是不是在for_each()的近处(比如就在for_each()调用出现处之前)定义 
该function object比较好? 唉, 真麻烦. 麻烦从何而来? 追根溯源, 在本质上 
Generic Programming和OOP是不同的. GP从算法开始, 而OOP围绕着数据在转. GP的 
function objects希望所有东西都是全局的, 不要有自定义的类, 这样实现算法才方便.  
(Stepanov在访谈中也是这么说的.)  但OOP则坚决反对全局的东西, 纯粹的OO语言(比如 
Java)甚至什么东西都是封装在类里面的. Application Framework同样如此. VCL是一个 
很OO的Framework, 它甚至采用单根继承树结构, 一切类均派生自TObject. 想让它和STL 
在深层次"亲密接触"可不容易. 从技术上来说, GP和OOP可以相辅相成, 但不能平分秋 
色. 只能以一者为主, 一者为辅.  
  
一项纯粹的技术看上去很美, 但当它和别的技术发生复杂的相互作用时问题即以几何级数 
产生. 我曾在一篇文章中说过C++并不是一种复杂的语言--当你割裂了看它的各个语言要 
素之时. 但是, 要素间的相互作用产生的复杂性会让初学者望而却步的. 你开发一个软 
件, 这个软件的众要素也是如此. 所以定义良好的界面才如此重要, 所以界面在现代方法 
学中才如此被强调. 界面应该很好地掩饰实作, 但事实往往并非如此. 信息隐藏很难尽 
善尽美, 要素间相互作用带来的问题往往需要你深入实作代码中剖根问底. 在前面举到 
的人工生命模拟平台的例子中你很可能需要看for_each()的实作(很简单)和vector的实作 
(也不复杂)代码才能了解问题之真实所在(因为BCB给出的错误信息很模糊), 那么STL提 
供抽象容器界面而封装容器实作之目的就没有达到.  
  
STL的代码风格, 以及许多东西, 都是和UNIX一脉相承的. 但这并不会给Windows程序员造 
成困扰. 真正关键的因素是, STL目前还不是一个无所不包的类库. 程序员建造软件系统时 
自然希望手中的建筑材料越丰富越好, Windows API是这样的材料, MFC, VCL都是. STL,  
Boost等类库也是. 如果不同"系列"的材料之间有复杂的相互作用会带来困扰, 那么看来只 
选用同一系列的材料是明智的. 怎么选择? 哪个系列提供了最丰富的功能, 这常常是影响 
选择的关键因素. 这里, Java的成功可以带给我们启示: 在任何一个领域, 它无论是开发 
效率还是运行速度还是其它方面都不是最优, 但是它的优点在于用一个单质平台覆盖了方 
方面面, 给我们提供了同一系列的功能最广泛的建筑材料. 所以, Java的流行是单一解决 
方案的魅力--人们不必为不同质材料间产生的不兼容问题而头痛. Sun及其Java联盟有实力 
提供这样的解决方案, 微软也有-- .NET就是一个非常优秀的解决方案. 在这样的环境中, 
 STL又能扮演什么样的角色呢? 仅仅是提供其它Application Framework/Class Library 
(比如JDK, WinForms)中容器和算法的优质替代品(而且伴随着潜在不兼容性的代价), 还是 

进入"主流建材市场"? 我们拭目以待.

原文链接:http://caoshanyou.blog.hexun.com/28012376_d.html

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值