读书笔记 effective c++ Item 54 让你自己熟悉包括TR1在内的标准库
1. C++0x的历史渊源
C++标准——也就是定义语言的文档和程序库——在1998被批准。在2003年,一个小的“修复bug”版本被发布。然而标准委员会仍然在继续他们的工作,一个“2.0版本”的C++标准预计在2009年被发布(虽然所有的工作很有可能在2007年底被完成)。直到现在,发布下一版C++的预计年份还没有被确定,这就解释了为什么人们把下一版C++叫做“C++0x”——C++的200x年版本。
C++0x可能会包含一些有趣的新的语言特性,但是大多数新C++功能将会以标准库附加物的形式被发布。我们已经知道了一些新的库功能将会是什么,因为它们已经在文档TR1(来自C++库工作组的Technical Report 1)中被指定了。在C++0x被官方正式发布之前,标准委员会保有对TR1的功能进行修改的权利,但是不太可能有大的修改。TR1预示了一个新的C++ release的开始——我们可能将其叫做标准C++ 1.1.如果你不熟悉TR1的功能,你不能被称作一个effective C++程序员,因为TR1中的功能对于各个种类的库和应用来说都是一种福利。
2. C++98标准库中都有什么?
在考察什么是TR1之前,回顾一下C++98版本标准库中的主要部分是很有价值的:
- 标准模版库(STL),包含容器(vector,string,,map等等);迭代器,算法(find,sort,transform等等);函数对象(less,greater等等);还有不同的容器和函数对象适配器(stack,priority_queue,mem_fun,not1等)
- Iostreams,包括对用户自定义buffering的支持,国际化IO,和预定义对象cin,cout,cerr和clog.
- 支持国际化,包括多区域的能力(multipue active locales)。像类型wchar_t(通常是16bits/char)和wstring(wchar_t组成的string)能够促进同Unicode一块工作。
- 支持对数值的处理,包括复杂数(complex)模板和纯数数组(valarray)。
- 异常继承体系,包括基类异常,派生类logic_error和runtime_error,还有继承自这些类的其他类。
- C89的标准库。在1989 C标准库中的所有东西同样被放入了C++。
如果你对上面的任何条款不熟悉,我建议你抽出足够的时间来看一些c++参考读物。
3. TR1中都包含什么?
TR1提出了14个新的组件(也就是程序库功能片段(pieces))。所有都被放入std命名空间中,更精确的说,是在内嵌命名空间tr1中。TR1组件 shared_ptr的全称因此就为std::tr1::shared_ptr。在这本书中,当讨论标准库的组件时,我通常会省略std::,但是我总是会为TR1组件加上前缀tr1::。
本书举例说明TR1中的一些组件:
- 智能指针 tr1::shared_ptr和tr1::weak_ptr。Tr1::shared_ptr的行为表现就像内建指针一样,但是它们追踪了有多少个tr1::shared_ptr指针指向一个对象。这被叫做引用计数。当最后的指针被销毁(也就是对象的引用计数变为0的时候),对象自动被delete。这在非环状数据结构中用于防止资源泄漏很好,但如果两个或者多个对象包含tr1::shared_ptr,这样一个环就形成了,这个循环可能相互持有对方对象的引用计数,而且都大于0——即使当所有的环的外部指针被销毁了(也就是当作为一个整体的对象组不能被使用了)。这时候就得使用tr1::weak_ptr,tr1::weak_ptr被设计为在非环状tr1::shared_base数据结构中的cycle-inducing 指针。Tr1::weak_ptr中没有引用计数。当指向对象的最后一个shared_ptr被销毁时,对象就会被delete,即使tr1::weak_ptr仍然指向这个对象。然而这样的指针会被自动被标记为失效。
Tr1::shared_ptr可能是TR1中最被广泛使用的对象。我在这本书中也使用了多次,包括在Item 13中,在这个条款中我解释了为什么它如此重要。(这本书没有weak_ptr的使用)
- Tr1::function,使用它可以表示任意可调用实体(例如,任何函数或者函数对象),只要这些实体的签名同目标签名是一致的。如果我们想使用它来注册一个回调函数,这个函数用int作为参数并且返回值为string。我们可以这么做:
void registerCallback(std::string func(int)); // param type is a function
// taking an int and
// returning a string
参数名字 func是可选的,所以registerCallback可以被声明为如下:
void registerCallback(std::string (int)); // same as above; param
// name is omitted
注意在这里“std::string(int)”为函数签名。Tr1:;function可以使registerCallback更加灵活,它可以接受任何可调用实体作为它的参数,这个调用实体使用int或者可以转换为Int的任何东西作为参数,返回值可以为一个string或者可以转换为string的任何东西。Tr1::function使用目标函数签名作为模板参数:
void registerCallback(std::tr1::function<std::string (int)> func);
// the param “func” will
// take any callable entity
// with a sig consistent
// with “std::string (int)”
这种灵活性非常有用,我已经在Item 35中展示过了。
- Tr1::bind,它能做STL绑定器bind1st和bind2nd能做的所有事情,甚至更多。不像pre-TR1中的binders,tr1::bind可以工作在const和非const成员函数中;可以使用按引用传递的参数;可以在没有其他函数帮助的情况下处理函数指针,所以在调用tr1::bind之前就没有必要同ptr_fun,mem_fun或者mem_fun_ref掺杂在一起了。简单说,tr1::bind是第二代绑定工具,它要远远好于第一代。我已经在Item 35中进行了举例。
我将剩下的TR1组件分成两部分。第一部分提供了相当独立的功能:
- Hash table 被用来实现set,multiset,map和multimap。每个新的容器都将模拟与pre-TR1相对应部分的接口。对于TR1中的hash table,最让人感到意外的是它们的名字:tr1::unordered_set,tr1::unordered_multiset,tr1::unordered_map和tr1::unordered_multimap。这些名字强调了它的内容不会像set,multiset或者multimap一样,TR1中hash-based的容器中的元素顺序是无序的。
- 正则表达式,包括在字符串上进行的基于正则表达式的搜索和替换功能,还有从一个匹配字符串到另一个匹配字符串的迭代等等。
- Tuple,它是对已经在标准库中存在的pair模板的泛化。相比于Pair对象会持有两个对象,tr1::tuple对象能够持有任意数量的对象。
- Tr1::array,本质上来说是一个“STL化的“数组,也就是一个支持像begin和end这样的成员函数的数组。Tr1::array的大小在编译期被固定;对象不使用动态内存。
- Tr1::mem_fn,为成员函数指针进行适配的在句法上的一个统一的方式。就像tr1::bind把C++98的bind1st和bind2nd的功能包含进来并对其进行扩展,tr1::mem_fn把C++98中的mem_fun和mem_fun_ref的功能包含进来并对其进行了扩展。
- Tr1::reference_wrapper,这是一个功能使得引用的行为表现就像对象一样。这使得创建一个行为表现就如同持有引用的容器成为可能(事实上,容器只能包含对象或者指针。)
- 随机数生成器(Random number generation)功能要比从C标准库中继承而来的随机函数更加优秀。
- 数学特殊函数(Mathematical special function),包括拉盖尔多项式,贝塞尔函数,完全椭圆积分(complete elliptic integrals)等等。
- C99兼容性扩展,为了将许多新的C99程序库的功能引入到C++中而设计的函数集合与模板。
TR1组件的第二个集合由为更加复杂的模板编程技术提供的支撑技术所组成,包括模板元编程(Item 48):
- 类型特性(Type traits),提供了一系列trait类(见Item 47)来为类型提供编译时信息。给定一个类型T,TR1的类型特性能够揭示T是否是一个内建类型,能否提供虚析构函数,是否是一个empty class(Item 39),是否可以隐式的转换为其它类型U,等等。TR1中的type traits同样也能够为一个类型揭示合适的对齐问题(alignment),这就为实现自定义内存分配函数的程序员提供了重要信息(Item 50)。
- Tr1::result_of,一个用来推导函数返回类型的模板。当实现模板的时候,能够引用从函数(模板)调用中返回回来的对象类型很重要,但是返回类型可以以复杂的方式来依赖函数的参数。在TR1中很多地方都使用到了Tr1::result_of。
虽然TR1中的一些功能(尤其是tr1::bind和tr1::mem_fn)只是将pre-TR1的一些组件纳入其中,但TR1只是标准库的额外添加物。没有TR1组件是对现存组件的替换,所以使用pre-TR1构建的遗留代码仍然有效。
4. 从哪里找到TR1实现
TR1本身只是一个文档。为了使用它指定的功能,你需要访问实现这些功能的代码。这些代码最后将会同编译器捆绑在一块发布,但是我写这本书是在2005年,如果在你的标准库实现中寻找TR1组件,可能会有一些遗漏。幸运的是,可以从其他地方进行搜寻:TR1 的14个组件中的10个是基于可以免费获得的Boost库(见Item 55)来实现的,所以如果你想了解和TR1类似(TR1-like)的功能,这会是一个很好的资源。这里我说“TR1-like”,因为虽然很多TR1功能是基于Boost库的,有一些地方Boost功能还没有同TR1规格完全匹配。很有可能但你读到这本书的时候,不仅对于从Boost 库进化而来的TR1组件,Boost中有了与其一致的实现,而且它同时提供了没有基于Boost的其余4个TR1组件的实现。
如果作为权宜之计你想使用Boost中的类似TR1的库,直到编译器同TR1实现一同被发布,你可能会使用一个命名空间的技俩。所有的Boost组件是在命名空间boost中,但是TR1组件将会在命名空间std::tr1中。你可以告诉编译器,把对std::tr1的引用当作对boost的引用来处理。像下面这样:
namespace std {
namespace tr1 = ::boost; // namespace std::tr1 is an alias
} // for namespace boost
从技术上来说,这会让你进入未定义行为的领域,因为正如在Item 25中解释的,不允许向std命名空间中添加任何东西。在实际情况下,看上去你不会遇到任何麻烦。当你的编译器提供了它们自己的TR1实现的时候,所有你需要做的就是移除上面的命名空间别名;引用std::tr1的代码仍然是有效的。
可能没有基于Boost库实现的TR1中的最重要的部分就是hash table了,但是hash tables已经存在很多年了,它们以hash_set,hash_multiset,hasp_map和hash_multimap命名。有可能你的编译器自带的库中已经包含这些模板了。如果没有,使用你最喜欢的搜索引擎去搜一下这些名字,因为你肯定能够找到一些源代码,无论是商业的还是免费的。
5. 总结
- 主要的标准C++库的功能包括STL,iostream和locales。C89标准库也被包含在内。
- TR1中添加了对智能指针的支持,广义的函数指针(tr1::function),hash-based 容器,正则表达式和10个其他的组件。
- TR1本身只是一个说明书。为了使用TR1,你需要一份实现。TR1组件实现的一份源码来自于Boost.
读书笔记 effective c++ Item 54 让你自己熟悉包括TR1在内的标准库的更多相关文章
- Effective C++ -----条款54:让自己熟悉包括TR1在内的标准程序库
C++ 标准程序库的主要机能由STL.iostream.locales 组成.并包含C99 标准程序库. TR1 添加了只能指针(例如 tr1::shared_ptr).一般化函数指针(tr1::fu ...
- 读书笔记 effective c++ Item 55 让你自己熟悉Boost
你正在寻找一个高质量的,开源的,与平台和编译器无关的程序库的集合?看一下Boost吧.想加入一个由雄心勃勃的,充满天赋的正致力于最高水平的程序库设计和实现工作的C++程序员们组成的团体么?看一下Boo ...
- 【54】让自己熟悉包括TR1在内的标准程序库
1.C++0X,不确定哪一年出来,意指200X版的C++ 2.C++标准程序库的主要机能有:STL,iostreams,locals等. 3.TR1:Technical Report 1,只是一份规范 ...
- 读书笔记 effective c++ Item 13 用对象来管理资源
1.不要手动释放从函数返回的堆资源 假设你正在处理一个模拟Investment的程序库,不同的Investmetn类型从Investment基类继承而来, class Investment { ... ...
- 读书笔记 effective c++ Item 16 成对使用new和delete时要用相同的形式
1. 一个错误释放内存的例子 下面的场景会有什么错? std::]; ... delete stringArray 一切看上去都是有序的.new匹配了一个delete.但有一些地方确实是错了.程序的行 ...
- 读书笔记 effective c++ Item 26 尽量推迟变量的定义
1. 定义变量会引发构造和析构开销 每当你定义一种类型的变量时:当控制流到达变量的定义点时,你引入了调用构造函数的开销,当离开变量的作用域之后,你引入了调用析构函数的开销.对未使用到的变量同样会产生开 ...
- 读书笔记 effective c++ Item 31 把文件之间的编译依赖降到最低
1. 牵一发而动全身 现在开始进入你的C++程序,你对你的类实现做了一个很小的改动.注意,不是接口,只是实现:一个私有的stuff.然后你需要rebuild你的程序,计算着这个build应该几秒钟就足 ...
- 读书笔记 effective c++ Item 45 使用成员函数模板来接受“所有兼容类型”
智能指针的行为像是指针,但是没有提供加的功能.例如,Item 13中解释了如何使用标准auto_ptr和tr1::shared_ptr指针在正确的时间自动删除堆上的资源.STL容器中的迭代器基本上都是 ...
- 读书笔记 effective c++ Item 47 使用traits class表示类型信息
STL主要由为容器,迭代器和算法创建的模板组成,但是也有一些功能模板.其中之一叫做advance.Advance将一个指定的迭代器移动指定的距离: template<typename IterT ...
随机推荐
- 1901: Zju2112 Dynamic Rankings
1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 5268 Solved: 2207[Su ...
- python list 切片实验
list[start:stop:step] >>> a_list=['hito','bb','cc','dd','ee','ff']>>> a_list[::-1] ...
- Spring Boot启动过程(六):内嵌Tomcat中StandardHost与StandardContext的启动
看代码有助于线上出现预料之外的事的时候,不至于心慌... StandardEngine[Tomcat].StandardHost[localhost]的启动与StandardEngine不在同一个线程 ...
- yii2.0使用之缓存
1.片段缓存(针对于视图中的某部分进行缓存): <?php 设置有效时间 $time=15; 缓存依赖,存入文件.当文件内容发生改变是才会刷新新内容 $dependecy=[ 'class'=& ...
- 初见 ThreadLocal 类
这个类能够将一个对象和一个线程绑定起来. 之所以写这个类是因为 DBUtils 工具类,在 JavaEE 经典三层结构中对于事务的操作,不方便放在 DAO 层,因为具有侵入性,只适合放在 Servic ...
- iOS用户行为追踪——无侵入埋点
本文章系作者原创文章,如需转载学习,请注明该文章的原始出处和网址链接. 在阅读的过程中,如若对该文章有不懂或值得优化的建议,欢迎大家加QQ:690091622 进行技术交流和探讨. 前言: 前几日 ...
- jquery-scrollstop
$(window) .on("scrollstart", function() { // Paint the world yellow when scrolling starts. ...
- nginx错误记录
症状: 安装phpBB3.1的最后一步完成安装之后,注册用户,浏览器崩溃.localhost的所有页面都打不开同时没有响应. Trace: 虽然打开了nginx.exe,但是进程中未发现服务. 重新电 ...
- JavaScript如何一次性展示几万条数据
有一位同事跟大家说他在网上看到一道面试题:“如果后台传给前端几万条数据,前端怎么渲染到页面上?”,如何回答? 于是办公室沸腾了, 同事们讨论开了, 你一言我一语说出自己的方案. 有的说直接循环遍历生成 ...
- [原]C#与非托管——封送和自动封送
之前说到了如何从C函数声明通过简单的查找替换生成一份C#的静态引用声明(C#与非托管——初体验),因为只是简单说明,所以全部采用的是基础类型匹配和自动封送.自动封送虽然能省去我们不少编码时间,但如果不 ...