免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 40355 | 回复: 239
打印 上一主题 下一主题

《Effective STL》 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-05-31 14:49 |只看该作者 |倒序浏览
Eff_STL_CN.pdf (1.04 MB, 下载次数: 2090)


前言
It came without ribbons! It came without tags!
It came without packages, boxes or bags!
——Dr. Seuss, How the Grinch Stole
Christmas!, Random House, 1957
我第一次写关于标准模板库的东西是在1995年,那时我决定把《More Effective C++》的最后一个条款写成一
个STL的简要概览。我早该更好地了解STL。不久以后,我开始收到一些邮件,问我什么时候写《Effective
STL》。
我把这个想法忍了几年。一开始,我对STL不够熟悉,所以不能给出关于它的建议。但随着时间的推移,我
STL的经验丰富了,而主要问题出现在了其他方面。当一个程序库的在效率和可扩展性设计上表现出突破性
的时候从来没有出过什么问题,但当开始使用STL时,这成了我无法预见的实际问题。迁移到一个几乎最简
单的STL程序都成了一个挑战,不光是因为库的实现变化多端,而且因为现有编译器对模板支持有好有坏。
STL的教材很难得到,所以学习“STL的编程方式”很难;但即使跨越了这个障碍,找到正确易学的参考文档
同样很困难。可能最令人畏惧的是,即使最小的STL使用错误也往往会导致一个编译器诊断的风暴——每一
个错误都有上千个字长,而且大多涉及的类,函数或模板在令人厌恶的源代码中并没有被提及——几乎都是
难以理解的。虽然我很钦佩STL和它背后的英雄们,但我还是觉得把STL推荐给实践中的程序员并不合适。我
不能肯定有可能有效地使用STL。
然后我开始注意到一些让我感到惊奇的事情。尽管有很多小问题,尽管只有令人消沉的文档,尽管编译器的
诊断信息像无线电信号杂音,但仍然有很多我的咨询客户在使用STL。而且,他们不只是玩玩而已,他们竟
然把STL用到了产品的代码中!这是一个革命。我知道STL表现出的是一流的设计,但任何让程序员必须忍受
移植性的麻烦、贫乏的文档和天书般的错误信息,却设计得很好的库也是不会被拥护的。我了解到越来越多
的专业程序员都认为即使一个实现得很不好的STL也比什么都没有要好得多。
此外,我知道STL的境遇只会越来越好。程序库和编译器对(它们的)标准兼容性会越来越好,更好的文档
将会出现(它已经存在了——请见从297页开始的“参考书目”),而且编译器的诊断会渐渐改进(在极大程
度上,我们仍然在等待,但条款49提供了怎样在其间应付的建议)。因此我决定插嘴,尽一份力量来支持
STL运动的萌芽。这本书就是结果:改善使用C++ STL的50个有效做法。
一开始,我计划在1999年下半年写这本书。带着这个想法,我组织了一个大纲。但我暂停和改变了进程。我
停止了写书的工作,开发了一个介绍性的STL训练课程,把它教给几拨不同的程序员。大约一年后,我回到
写书的工作中,根据我在训练课程中得到的经验意味深长地修改了大纲。和我的《Effective C++》成功的方
法一样,它们都是以真正的程序员所面对的问题为基础的。我希望《Effective STL》同样从事于STL编程的实
践方面——这是对专业开发人员最重要的方面。
我总是在寻找能让我加深对C++理解的方法。如果你对STL编程有新的建议或者如果你对这本书有什么评论
的话,请让我知道。另外,让本书尽可能地正确是我继续的目标,所以如果谁挑出了本书的任何一个错误请
务必告诉我——不论是技术、语法、错别字或任何其他东西——我将在本书再次印刷的时候,把第一位挑出
错误的读者大名加到致谢名单中。请将你的建议、见解、批评发至 estl@aristeia.com
我维护有本书第一次印刷以来的修订记录,其中包括错误更正、文字修润、以及技术更新。这份记录可以从
《Effective STL》的勘误表网站http://www.aristeia.com/BookErrata/estl1e-errata.html得到。
如果你希望在我对此书作出修改时得到通知,我想你应该加入我的邮件列表。我用这个列表来通知对我的C+
+工作感兴趣的人。详情请见http://www.aristeia.com/MailingList/
SCOTT DOUGLAS MEYERS
http://www.aristeia.com
STAFFORD, OREGON
APRIL 2001

[ 本帖最后由 haoji 于 2008-6-1 13:38 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2008-05-31 14:54 |只看该作者
致谢
在我理解STL、建立关于它的培训课程和写这本书的大约两年时间里,我得到了大量帮助。在我所有帮助的
来源中,有两个特别重要。 第一个是Mark Rodgers。当我建立它们时,Mark慷慨地自愿检查我的培训材料,
而且我从他那里比从其他人那里学到更多关于STL的东西。他也作为本书的技术评论家,再次提供改进了几
乎每个条款的观点和见解。
另一个突出的信息源是几个有关C++的Usenet新闻组,特别是comp.lang.c++.moderated(“clcm”),comp.
std.c++和microsoft.public.vc.stl。十多年来,我已经依赖于像这样的新闻组中的参加者来回答我的问题和挑战
我的思想,而且很难想象如果没有他们我该怎么办。我非常感谢Usenet社区对本书和我早先关于C++的出版
物的帮助。
多种出版物形成了我对STL的理解,其中最重要的列在了参考书目里。我对Josuttis的《The C++ Standard
Library》[3]倾向特别大。
本书基本上是其他人做的一些见解和观点的摘要,虽然有一些想法是我自己的。我已经努力跟踪我在哪里学
到了什么,但这个任务是没希望的,因为一个典型的条款包含在很长时间内从很多来源收集的信息。所以跟
踪是不完全的,但是我已经尽力了。请注意在这里我的目标是总结一个想法或技术我第一次是在哪里学到
的,而不是一个想法或技术最先在哪里开发或谁先想到了它。
在条款1,我的基于节点的容器对事务性语义提供了更好的支持的观点是基于Josuttis的《The C++ Standard
Library》第5.11.2节[3]。条款2包括一个来自Mark Rodgers的关于当分配器类型改变之后typedef起了什么作用的
例子。条款5由Reeves的《C++ Report》专栏《STL Gotchas》[17]激发而来。条款8源自Sutter的《Exceptional C
++》[8]的条款37,而Kevlin Henney提供了关于auto_ptr的容器在实际中为什么失效的重要细节。在Usenet的帖
子里,Matt Austern提供了分配器什么时候很有用的例子,而我把他的例子包含在条款11。条款12基于SGI STL
网站[21]上关于线程安全性的讨论。条款13关于引用计数在多线程环境下的性能影响的材料来自Sutter关于这
个主题的文章[20]。条款15的主意来自Reeves的《C++ Report》专栏《Using Standard string in the Real World,
Part 2》[18]。在条款16,Mark Rodgers提出了我演示的让C API直接把数据写入一个vector的技术。条款17包含
的信息来自Siemel Naran和Cart Barron在Usenet的帖子。条款18是我从Sutter的《C++ Roport》专栏《When Is a
Container Not a Container?》[12]偷来的。在条款20,Mark Rodgers捐献了把一个指针通过一个解引用仿函数转
换成一个对象的主意,而Scott Lewandowski提出了我呈现的DereferenceLess版本。条款21源自Doug Harrison在
microsoft.public.vc.stl的帖子,但我决定把那个条款的重点放在相等。条款22基于Sutter的《C++ Report》专栏
《Standard Library News: sets and maps》[13];Matt Austern帮我了解了标准委员会的库问题#103的情况。条款23
是从Austern的《C++ Report》文章《Why You Shouldn't Use set -- and What to Use Instead》[15]得到的灵感;
David Smallberg为我的DataCompare实现做出了一个优雅的改进。我对Dinkumware的散列容器的描述基于

论坛徽章:
0
3 [报告]
发表于 2008-05-31 14:54 |只看该作者
Plauger的《C/C++ Users Journal》专栏《Hash Tables》[16]。Mark Rodgers并不同意条款26的全部建议,但那个
条款的早先动机是他的有些容器的成员函数只接受iterator类型的实参的观点。我对条款29的处理来自和扩充
自Matt Austern和James Kanze发起的Usenet讨论;我也受到Kreft和Langer的《C++ Report》文章《A
Sophisticated Implementation of User-Defined Inserters and Extractors》[25]的影响。条款30是因为Josuttis的《The
C++ Standard Library》[3]第5.4.2节的讨论。在条款31,Marco Dalla Gasperina捐献了使用nth_element计算中值
的例子,而使用那个算法来寻找百分点直接来自Stroustrup的《The C++ Programming Language》[7]第18.7.1
节。条款32受到Josuttis的《The C++ Standard Library》[3]第5.6.1节的材料影响。条款35源自Austern的《C++
Report》专栏《How to Do Case-Insensitive String Comparison》[11],而James Kanze和John Potter的clcm帖子帮我
精炼了我对出现这个问题的理解。Stroustrup的copy_if实现,也就是我在条款36演示的,来自他的《The C++
Programming Language》[7]第18.6.1节。条款39受到Josuttis的出版物很大的推动,他在《The C++ Standard
Library》[3]里写了“带状态的判定式”,在标准库问题#92,和他的《C++ Report》文章《Predicates vs.
Function Objects》[14]。在我这里,我使用了他的例子并接受他提出的一个解决方案,虽然术语“纯函
数”是我发明的。Matt Austern证实了我在条款41的关于属于mem_fun和mem_fun_ref的历史的猜想。条款42可
以追溯到当我考虑违反那个方针时Mark Rodgers给我的一个演讲。Mark Rodgers也对条款44的观点负责,也就
是搜索map和multimap时,非成员函数检查每个pair的两个组件,而成员函数的搜索只检查第一个(键)组
件。条款45包含来自多个clcm贡献者的信息,包括John Potter、Marcin Kasperski、Pete Becker、Dennis Yelle和
David Abrahams。David Smallberg提醒我在进行基于等价的搜索和对有序序列容器的计数上equal_range的效
用。Andrei Alexandreseu帮我了解了我在条款50提到的“到引用的引用问题”的情况,而我从Mark Rodgers提
供的Boost网站[22]上类似的例子模仿出这个问题的例子。
当然,附录A的材料归功于Matt Austern。我感谢他不仅允许我在本书里包含它,而且还把它改得比原来更
好。
好的技术书需要彻底的出版前检查,而很幸运我受益于一群非同寻常的天才技术评论家的见解。Brian
Kernighan和Cliff Green为部分草稿提供了早期意见,而手稿的完整版本由Doug Harrison、Brian Kernighan、
Tim Johnson、Francis Glassborow、Andrei Alexandrescu、David Smallberg、Aaron Campbell、Jared Manning、
Herb Sutter、Stephen Dewhurst、Matt Austern、Gillmer Derge、Aaron Moore、Thomas Becket、Victor Von,当然
还有Mark Rodgers细察。Katrina Avery做了审稿。
准备一本书最富挑战性的部分之一是找到好的技术评论家。我感谢John Putter把我介绍给Jared Manning和
Aaron Campbell。
Herb Sutter好心地同意作为我在微软的Visual Studio .NET beta版上有些STL测试程序编译、运行和报告方面的
行为的代理,而Leor Zolman担任测试在本书里的所有代码的极为艰巨的工作。当然,剩余的任何错误都是我
的过错,并非Herb或者Leor的。
Angelika Langer让我看到了STL函数对象一些方面的不明状态。有关函数对象,本书说的比可能的要少,但它

论坛徽章:
0
4 [报告]
发表于 2008-05-31 14:55 |只看该作者
所说的基本上保证是真的。至少我希望它是。
本书的这次印刷比早期印刷的好,因为我指出了下面这些眼尖的读者发现的问题:Jon Webb、Michael
Hawkins、Derek Price、Jim Seheller、Carl Manaster、Herb Sutter、Albert Franklin、George King、Dave Miller、
Harold Howe、John Fuller、Tim McCarthy、John Hershberger、Igor Mikolic-Torreira、Stephan Bergmann、Robert
Allan Schwartz、John Potter、David Grigsby、Sanjay Pattni、Jesper Andersen、Jing Tao Wang、André Blavier、
Dan Schmidt、Bradley White、Adam Petersen、Wayne Goertel和Gabriel Netterdag。我感谢他们的在改进
《Effective STL》方面所提供的帮助。
我在Addison-Wesley的合作者包括John Wait(我的编辑,现在是高级VP),Alicia Carey和Susannah Buzard(他
的助手n和n+1),John Fuller(产品协调员),Karin Hansen(封面设计者),Jason Jones(都是技术领袖,特
别是关于Adobe喷薄而出的有魔力的软件),Marty Rabinowitz(他们的老板,但他也工作),以及Curt
Johnson,Chanda Leary-Coutu和Robin Bruce(都是销售员,但仍然非常好)。
Abbi Staley总能把星期日的午餐变成令人愉快的体验。
虽然在这之前有六本书和一张CD,我的妻子,Nancy,用她常有的自制力容忍了我研究和写作的要求,而且
当我最需要的时候能给我鼓励和支持。她从未忘记提醒我生活比C++和软件重要。
然后是我们的狗,Persephone。当我写这个的时候,正是她的第六个生日。今晚,她和Nancy和我将去Baskin-
Robbins吃冰淇淋。 Persephone将享受香草。一铲,在一个杯子里。走咯。

论坛徽章:
0
5 [报告]
发表于 2008-05-31 14:58 |只看该作者
Center of STL Study
——最优秀的STL学习网站
导读
你已经熟悉了STL。你知道怎么建立容器,迭代它们的内容,添加删除元素和应用常见算法,比如find和sort。但你并不
满足,你不能摆脱STL所提供的超过它们能带来的好处的感觉。应该简单的任务并非那样。应该直截了当的操作确有资
源泄漏或错误行为。应该高效的过程却需要比你希望给它们的更多的时间和内存。是的,你知道怎么使用STL,但你不
确定你在有效地使用它。
我为你写了这本书。
在《Effective STL》中,我解释了怎样结合STL组件来在库的设计得到最大的好处。这样的信息允许你对简单、直接的问
题开发简单、直接的解决方案,也帮你对更复杂的问题设计优雅的方法。我描述了常见的STL使用错误,而且向你演示
怎么避开它们。那帮助你躲开闪资源漏、不可移植的代码和未定义的行为。我讨论了优化代码的方法,所以你能使STL
表现得像它应该的那样快速、光滑。
本书里的信息将使你成为一个更好的STL程序员,它将让你成为一个更高产的程序员。而且它将让你成为一个更愉快的
程序员,使用STL很有趣,但是有效地使用它更为有趣,这种有趣是它们必须把你拽离键盘,因为你不能相信你争拥有
的好时光。即使对STL的匆匆一瞥也能发现它是一个非常酷的库,但这份酷比你可能想象的更宽更深。我在本书的一个
主要目标是传达给你这个库有多神奇,因为在我编程的差不多30年里,我从未见过任何像STL的东西。你或许也没有。
定义、使用和扩展STL
没有“STL”的官方定义,而且当人们使用这个术语时,不同的人表示的是不同的东西。在本书中,“STL”的意思是
与迭代器合作的C++标准库的一部分。那包括标准容器(包括string),iostream库的一部分,函数对象和算法。它不包
括标准容器适配器(stack、queue和priority_queue)以及bitset和valarray容器,因为它们缺乏迭代器支持。它也不包括数
组。真的,数组以指针的形式支持迭代器,但数组是C++语言的一部分,并非库。
技术上,我的STL的定义排除了标准C++库的扩展,特别是散列容器,单链表,rope和多种非标准函数对象。虽然如
此,一个有效的STL程序员需要知道这样的扩展,因此我在合适的地方提到了它们。的确,条款25致力于非标准散列容
器的概述。它们现在不在STL里,但类似它们的东西几乎肯定将要进入标准C++库的下一个版本,而在窥见未来是有价
值的。
存在STL扩展的原因之一是STL是被设计为可扩展的库。不过,在本书里,我关注于使用STL,而不是给它添加新的组
件。例如,如果你发现,我没有说多少关于写你自己的算法的东西,而且我根本没有在写新容器和迭代器上提供指导。
我相信在你着手增加它的能力之前,掌握STL已经提供的东西很重要,所以那是我在《Effective STL》里关注的。当你决
定建立你自己STLesque组件时,你将在像Josuttis的《The C++ Standard Library》[3]和Austern的《Generic Programming and
the STL》[4]这样的书里找到建议。我确实在这本书里讨论的STL扩展的一个方面是写你自己的函数对象。你不可能在不
知道怎么写自己的函数对象的情况下有效地使用STL,所以我为这个主题投入了整整一章(第6章)。

论坛徽章:
0
6 [报告]
发表于 2008-05-31 14:58 |只看该作者
引用
先前段落中对Josuttis和Austern的书的引用演示了我怎么处理书目引用的。通常,我试图提及引用的足够信息以便已经熟
悉它的人能够鉴别出来。例如,如果你已经知道这些作者的书,就不必转向参考书目那里查明[3]和[4]提及的你已经知
道的书。当然,如果你不熟悉一个出版物,参考书目(从第225页开始)会给你全面的引用。
我经常引用三个一般没有使用引用编号的东西。第一个是C++国际标准[5],我通常把它简称为“标准”。其他两个是
我早先关于C++的书,《Effective C++》[1]和《More Effective C++》[2]。
STL和标准
我经常提及C++标准,因为《Effective STL》专注于可移植的,与标准一致的C++。理论上,我在这本书里演示的一切都
可以用于每个C++实现。实际上,那不是真的。编译器的缺陷和STL实现凑合成防止一些有效的代码编译或表现出它们
应该有的行为。那是很常见的情况,我描述了这些问题,而且解释了你应该怎么变通地解决他们。
有时候,最容易的变通办法是使用另一个STL实现。附录B给一个这种情况的例子。实际上,STL用得越多,编译器和库
实现的区别就越重要。程序员在设法让合法的代码编译时遇到困难,他们通常责备他们的编译器,但对于STL,编译器
可能是好的,而STL实现是不良的。为了强调你得依赖编译器和库实现的事实,我使用你的STL平台。一个STL平台是一
个特定编译器和一个标准模板库特定实现的组合。在本书里,如果我提及一个编译器问题,你能确信我意思是编译器有
问题。但是,如果我说你的STL平台有问题,你应该理解为“可能是编译器缺陷,可能是库缺陷,或许都有”。
我一般提及你的“编译器们”——复数。那是我长期相信你通过确保代码可以在多于一个的编译器上工作的方法来改进
你的代码质量(特别是移植性)的产物。此外,使用多个编译器一般可以简化拆解由STL的使用不当造成的错误信息难
题。(条款49致力于解码此类消息的方法。)
关于与标准一致的代码,我强调的另一个方面是你应该避免构造未定义行为。这样的构造可能在运行期做任何事情。不
幸的是,这意味着它们可能正好做了你想要的,而那会导致一种错误的安全感。太多程序员以为未定义行为总会导致一
个明显的问题,例如,一个分段错误或其他灾难性的错误。未定义行为的结果实际上更为狡猾,例如,破坏极少引用的
数据。它们也可以通过程序运行。我发现一个未定义行为的好定义是“为我工作,为你工作,在开发和QA期间工作,
但在你最重要的用户面前爆炸了”。避免未定义行为很重要,所以我指出了它会出现的通常情况。你应该训练你自己警
惕这样的情况。
引用计数
讨论STL而没有提及引用计数是几乎不可能的。正如你将在条款7和33看见的,基于指针的容器的设计几乎总要导致引用
计数。另外, 很多string实现内部是引用计数的,而且,正如条款15解释的,这可能是一个你不能忽视的实现细节。在
本书里,我认为你已经熟悉引用的基础。如果你不是,大多数中级和高级C++教材都覆盖了这个主题。例如,在
《More Effective C++》里,相关材料是在条款28和29。如果你不知道引用计数是什么而且你不喜欢学习,不要担心。你
也可以读完本书,虽然这里那里可能有一些句子不像它们应该的那么有意义。

论坛徽章:
0
7 [报告]
发表于 2008-05-31 14:59 |只看该作者
string和wstring
我关于string说的任何东西都可以相等地应用到给它的宽字符兄弟,wstring。类似地,任何时候我提及string和char或char*
之间的关系,对于wstring和wchar_t或wchar_t*之间的关序也是正确的。换句话说,只是因为我在本书里不明确地提及宽
字符字符串,不要以为STL不能支持它们。它也像基于char的字符串一样支持它们。它必须。string和wstring都是同一个
模板的实例化,basic_string。
术语,术语,术语
这不是STL的入门书,所以我认为你知道基本的东西。仍然,下面的术语十分重要,我感到需要强迫复习它们:
● vector、string、deque和list被称为标准序列容器。标准关联容器被是set、multiset、map和multimap。
● 迭代器被分成五个种类,基于它们支持的操作。简要地说,输入迭代器是每个迭代位置只能被读一次的只读迭
代器。输出迭代器是每个迭代位置只能被写一次的只写迭代器。输入和输出迭代器被塑造为读和写输入和输出
流(例如,文件)。因此并不奇怪输入和输出迭代器最通常的表现分别是istream_iterator和ostream_iterator。
前向迭代器有输入和输出迭代器的能力,但是它们可以反复读或写一个位置。它们不支持operator--,所以它们
可以高效地向前移动任意次数。所有标准STL容器都支持比前向迭代器更强大的迭代器,但是,正如你可以在条
款25看到的,散列容器的一种设计可以产生前向迭代器。单链表容器(在条款50提到)也提供前向迭代器。
双向迭代器就像前向迭代器,除了它们的后退可以像前进一样容易。标准关联容器都提供双向迭代器。list也
有。
随机访问迭代器可以做双向迭代器做的一切事情,但它们也提供“迭代器算术”,即,有一步向前或向后跳的
能力。vector、string和deque都提供随机访问迭代器。指进数组的指针可以作为数组的随机访问迭代器。
● 重载了函数调用操作符(即,operator())的任何类叫做仿函数类。从这样的类建立的对象称为函数对象或仿函
数。STL中大部分可以使用函数对象的地方也都可以用真函数,所以我经常使用术语“函数对象”来表示C++函
数和真的函数对象。
● 函数bind1st和bind2nd称为绑定器。
STL的一个革命性方面是它的复杂度保证。这些保证约束了任何STL操作允许表现的工作量。这极好,因为它可以帮你
确定同一问题不同方法的相对效率,不论你使用的是什么STL平台。不幸的是,如果你不了解计算机科学的行话,在复
杂度保证后面的专有名词可能会把你弄糊涂。这里有一个关于我在本书里使用的复杂度术语的快速入门。每个都引用了
它作为n的函数做一件事情要多久,n是容器或区间的元素数目。
● 以常数时间执行的操作的性能不受n的改变而影响,例如,向list中插入一个元素是一个常数时间操作。不管list有
一个还是一百万个元素,插入都花费同样数量的时间。
不要太照字面理解占用“常数时间”。 它不意味着做某些事情所花费时间的数量是字面上的常数,它只表明不

论坛徽章:
0
8 [报告]
发表于 2008-05-31 14:59 |只看该作者
被n影响。例如,两个STL平台可能花费非常不同数量的时间执行相同的“常数时间”操作。如果一个库比另一
个有更复杂的实现,或如果一个编译器执行了充分的更积极优化的时候,这就会发生。
常数时间复杂度的一个变体是分摊常数时间。以分摊常数时间运行的操作通常是常数时间的操作,但偶尔它们
花的时间也取决于n。分摊常数时间操作通常以常数时间运行。
● 当n变大时,以对数时间运行的操作需要更多的时间运行,但它需要的时间以与n的对数成正比的比率增长。例
如,在一百万个项上的一次操作预计花费大约在一百个项上三倍的时间,因为log n3 = 3 log n。在关联容器上的
大多数搜寻操作(例如,set::find)是对数时间操作。
● 以线性时间运行的操作需要的时间以与n成正比的比率增长。标准算法count以线性时间运行,因为它必须查看给
定区间中的每个元素。如果区间的大小扩大了三倍,它也必须做三倍的工作,而且我们期望它大约花费三倍时
间来完成。
通常,常数时间操作运行得比要求对数时间的快,而对数时间操作运行得比线性的快。当n变得足够大时,这总是真
的,但对于n相对小的值,有时候更差理论复杂度的操作可能或胜过更好理论复杂度的操作。如果你想对知道更多STL
复杂度保证的东西,转向Josuttis的《The C++ Standard Library》[3]。
术语的最后一个要注意的东西是,记住map或multimap里的每个元素都有两个组件。我一般叫第一个组件键,叫第二个
组件值。以
map<string, double> m;
为例,string是键,double是值。
代码例子
这本书充满了例子代码,当我引入每个例子时我都作了解释。不过仍然值得提前知道一些事情。
你可以从上面map的例子看到我通常忽略#include,而且忽视STL组件在namespace std里的事实。当定义map m,我可以
这么写,
#include <map>
#include <string>
using std::map;
using std::string;
map<string, double> m;
但我喜欢让我们省掉这些噪音。

论坛徽章:
0
9 [报告]
发表于 2008-05-31 15:00 |只看该作者
当我为一个模板声明一个形式类型参数时,我使用typename而不是class。即,不这么写,
template<class T>
class Widget { ... };
我这么写:
template<typename T>
class Widget { ... };
用这个场景里,class和typename表示完全相同的东西,但我发现typename能更清楚地表示我通常想要说的:T可以是任何
类型;不必是一个类。如果你喜欢使用class来声明类型参数,那也可以。在这个场景里是用typename或class完全是风格
的问题。
在另一个场景里,这不再是风格问题。为了避免潜在的解析含糊(我将提供给你细节),你被要求在依赖形式类型参数
的类型名字之前使用typename。这样的类型被称为依赖类型,一个例子将帮助阐明我所说的。假设你想为函数写一个模
板,给定一个STL容器,返回容器中的最后一个元素是否大于第一个元素。这是一种方法:
template<typename C>
bool lastGreaterThanFirst(const C& container)
{
if (container.empty()) return false;
typename C::const_iterator begin(container, begin());
typename C::const_ierator end(container.end());
return *--end > *begin;
}
在这个例子里,局部变量begin和end的类型是C::const_iterator。const_iterator是依赖形式类型参数C的一种类型。因为C::
const_iterator是一种依赖类型,你被要求在它之前放上typename这个词。(一些编译器错误地接受没有typename的代
码,但这样的代码不可移植。)
我希望你注意到了在上面例子里我对颜色的使用。那是为了让你的注意力集中于特别重要的部分代码。通常,我加亮相
关例子之间的差别,正如我在Widget例子里演示两种可能的声明参数T的方法。用于唤起例子中特别值得注意的部分的
颜色也延伸到图表。例如,来自条款5的这张图使用颜色来区分当新元素被插入list时受影响的两个指针:

论坛徽章:
0
10 [报告]
发表于 2008-05-31 15:05 |只看该作者
我也为章号使用颜色,但这样的使用完全没有理由。这作为我的第一本两色的书,我希望你能原谅我的一点色彩丰富。
我最喜爱的参数名中的有两个是lhs和rhs。它们分别代表“左手边”和“右手边”,而且当声明操作符时,我发现它们
特别有用。 这是来自条款19的一个例子:
class Widget { ... };
bool operator==(const Widget& Ihs, const Widget& rhs);
当这个函数在这样的场景下被调用时,
if (x == y) ... // 假设x和y是Widget
x,在“==”的左边,在operator==里面被称为lhs,而y被称为rhs。
至于类名Widget,与GUI或者工具无关。这指示我为“做某件事的某个类”使用的名字。有时,正如第7页上的,
Widget是一个类模板而不是一个类。在这样的情况里,你可能发现我仍然称Widget为一个类,即使这真的是一个模板。
只要对讨论的东西不会产生歧义,忽略类和类模板、结构体和结构体模板、函数和函数模板之间的差别就不会伤害任何
人。在可能混淆的情况下,我会分清模板和它们产生的类、结构体和函数。
涉及效率的条款
我考虑过在《Effective STL》中包含一章关于效率的,但我最后决定当前的组织是更好的。仍然,许多项目关注与减少
空间和运行期需要。为了方便你的性能提高,这里有一张包含实际上关于效率的章节的表:
条款4:用empty来代替检查size()是否为0 23
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP