STL喜欢用第三人称说话,也喜欢给你带来独家新闻:
VisualStudio2008ServicePack1(VC9SP1)包含最初在中发布的TR1和MFC库扩展 Visual C++ 2008特征包刷新 . 但是等等! VC9SP1还包含许多针对TR1和MFC的美味修复程序。 (对于TR1,“many”是16;对于MFC,“多”是60或更多!)
作为微软中的C++标准库和Tr1实现的当前维护者,STL已经编译了VC9 SP1中的Tr1修复的详尽列表。 但首先! 呼喊声必须发送给P.J.普劳格和克里斯托弗J。步行者 纯粹的器皿 他孜孜不倦地致力于实现这些修补程序中的大部分,以及微软的编译器前端忍者 乔纳森洞穴 ,修复了TR1暴露的令人讨厌的编译器错误。
三个最重要的修复是:
*正则表达式匹配的巨大性能改进。
*TR1对象的STL容器的全面性能改进(例如vector
*允许tr1::function使用非常量函数调用运算符存储函数对象的修复。
这是详尽的清单:
1.STL算法search()不再错误触发u有u迭代器u调试断言。 (search()不是TR1的一部分,但这就是为什么这里提到它: VC9功能包刷新中修复了一个严重的搜索错误,即从VC8 SP1到VC9 RTM的回归,其中谓词版本尝试使用operator==()。 但是,修复包含了这个不太严重的缺陷,它及时被发现,并在VC9 SP1中得到了真正的修复。)
2.均匀随机分布不再无限循环。
3、<随机>报头已被检修,包含了许多C++ 0x改进。
4.伪随机数生成器的复制构造函数现在行为正常。 (这是一个微妙的错误,在重载解析期间,模板构造函数提供了比副本构造函数更好的匹配。)
5.从启用共享此复制构造函数和复制赋值运算符已更正。 (这影响了从enableu sharedu from u This派生的类,并且不影响sharedu ptr的其他使用。)
6.共享的ptr
7.tr1::function现在可以使用非常量函数调用运算符存储函数对象。 (这是一个严重的问题。)
8.正则表达式匹配的性能得到了极大的提高。 (一般来说,TR1 Regex与Boost.Regex 1.35.0一样快或更快。 对于一些正则表达式来说,TR1正则表达式仍然比Boost慢,比如那些以“可爱的毛茸茸的小猫”之类的替换形式为主的正则表达式,但是与功能包刷新相比,它们的性能也有了显著的提高。 正在研究VC10的进一步性能改进。)
9.无序集(etc)和散列集(etc)的性能得到了显著提高。 (tr1::unorderedu set和stdext::hashu set共享相同的实现。 erase()静止出现性能问题,正在针对VC10进行调查。)
10.的结果u现在接受对函数的引用。
11.is函数和is成员函数指针现在可以正确处理可变参数。
12.多态性现在可以正常工作了。 (它以前对std::iostream这样的类给出了错误的答案。 这是Jonathan Caves修复的一个编译器错误。)
13.现在可以通过在内存中定义u DO u NOT u DECLARE u INTERLOCKED u intrinsics来抑制
14.memu fn()现在可用于抽象基类。 (这个令人惊讶的错误是由库和编译器错误引起的,两者都已修复。 其他代码可能会受益于此编译器修复。)
15.是u pod并且u琐碎的u构造函数现在可以正常工作。 (他们以前对某些不常见的课程给出了虚假的答案。)
16.交换优化(之前在 这篇博客文章 )现在实际用于TR1对象。
#16条值得解释。
STL容器(vector、deque、list、set、multiset、map、multimap)是“可快速交换的”;x、 swap(y)和swap(x,y)是常数时间、无失效、无迭代器失效。 (你可能还记得VC8 交换错误 打破了最后一个非常重要的部分。) std::string swap()也是常量时间和nofail,尽管它会由于较小的字符串优化而使迭代器无效。
恒定时间意味着交换STL容器是通过交换它们的内脏(它们的指针,无论是指向向量的内存块、列表的双链接节点还是映射的二叉树节点)来实现的。 这比复制“Container temp=a;a=b;b=温度会涉及到。
现在,当向量经历重新分配时,它必须将当前元素从旧内存块复制到新内存块。 当您有一个STL容器向量(vector
交换优化出现在VC8中(可能更早,但STL还没有检查),这是一种模板魔法,STL容器被标记为具有快速交换。 当向量
许多TR1对象,例如无序的u集和匹配的u结果以及共享的u ptr,也有快速交换。 这是因为它们要么是容器(如无序的u集),要么是包装容器(如匹配的u结果),要么不是容器,但它们具有指向填充结构的相同指针(如共享的u ptr)。 因此,Dinkumware和STL非常努力地为所有TR1对象提供快速交换,并适当地标记它们以便通过交换优化来获取。
不幸的是,这只是打破了在功能包刷新! 问题很微妙。 STL在namespace std中提供swap()free函数,该函数执行三步舞,对任何可复制和可分配的对象都有效(但可能很慢)。 其思想是,具有快速可交换类的用户,除了提供member swap()之外,还可以在名称空间std中完全专门化swap()以用于他们的类。 (一般来说,用户*不应该*向命名空间std添加任何内容。 但是,标准模板可以完全或部分专用于用户类;这是本标准第17.4.3.1/1段。) 这很管用哦。
但是,具有快速可交换类*模板*的用户必须做一些不同的事情。 关于C++的一个不被普遍理解的事实是,没有像函数模板的局部专门化这样的事情。 任何看起来像部分特化的东西实际上都是一个过载。 (只有类可以部分专用化。) 实际上,重载的行为与用户认为的函数模板的部分专门化的工作方式非常相似,每个人都相处得很愉快。
但这意味着您不能将swap()的重载添加到namespace std,即使您认为它们看起来像神话中的部分专门化。 因此,如果您有一个快速可交换的类模板,则需要在与类模板相同的命名空间中提供一个swap()free函数,该函数可以通过参数相关查找(ADL,以前称为Koenig Lookup,描述较少)。
(不,这不是很理想。 交换是一个非常基本的操作,它确实应该在核心语言中得到认可,比如复制,但现在改变它已经太晚了。)
因此,TR1几乎是标准的一部分,但不完全是标准的一部分,它在名称空间std::TR1中提供了一堆快速可交换的内容,并在std::TR1中定义了swap()的重载。 TR1类是可快速交换的,被注释为这样,并且被vector和其他一些地方的现有交换优化机制检测为这样。 那它为什么不起作用呢?
原来,交换优化是通过调用限定的std::swap()来执行的。 大多数人在他们的头脑中不做C++名字查找来娱乐,但重要的是要知道:限定名称查找禁用ADL。 哦哦! 因此,选择了std::swap()的一般实现(执行缓慢的三步复制舞蹈),而不是std::tr1::swap()的特定实现,用于共享的u ptr
(为什么使用限定呼叫? 另一个名称查找的微妙之处是:像swap()这样的非限定调用激活了非限定名称查找(通常,每个人都熟悉)和ADL(每个人都应该熟悉)。 通常,它们找到的函数集的并集用于重载解析(选择实际调用的函数)。 但如果不合格的名称查找找到一个成员函数,ADL将被绕过;这是本标准第3.4.2/2a段。 因此,在定义成员swap()的类中,调用unqualified swap()不会激活ADL,甚至找不到std::swap()——它会找到成员swap()。 因此,在VC的标准库实现中,限定调用已成为常规。)
修复方法是定义一个包装器std::Swap_adl(),它调用unqualified Swap(),正确激活adl。 现在,只要需要adl,STL就会调用std::u Swapu adl()。 (当不需要ADL时,它会继续调用std::swap(),例如交换内置文件时)。 与所有的_前导u下划线u大写名称一样,用户不应该自己调用std::u Swap u adl()(它可能在将来的版本中更改或消失)。 您可以通过在自己选择的名称空间中定义自己的包装器来执行完全相同的技巧,包装器包含“using namespace std;”以及对swap()的非限定调用。 (如果您查看std::u Swapu adl()的实现,它缺少using指令—它已经存在于名称空间std中,这与您可以定义的任何内容都不同。)
最终的结果是,当一个向量
请注意,这些修复都不在sp1beta中,随着featurepack的完成,sp1beta将进行分支以供发布。
斯蒂芬T。拉瓦维
Visual C++库开发人员