VC Team Blog - TR1实现问答

原文: Q&A on our TR1 implementation

大家好,我是Stephan,Visual C++库函数组的程序员。Visual Studio 2008扩展功能库的beta版已经发布(可以在 这里下载,文档在 这里),其中包含了TR1的实现,我想在这里回答一些关于TR1的问题
 
Q. 扩展功能库是针对哪个Visual C++版本的?
A. 扩展功能库是针对Visual C++ 2008的RTM版本(VC9)。目前扩展功能库尚不支持以下版本的VC
  • VC9 Express
  • VC9 RTM以前的版本(比如VC9 beta 2)
  • 老版本的VC(比如VC8)

Q. 是不是把新增的头文件拷到VC/include目录下就可以使用了?
不是。VC9的TR1除了新增了一些头文件之外(比如<regex>),还对原有的头文件进行了修改(比如<memory>),并对原有的CRT库做了更新(比如msvcp90.dll)
因为这次的扩展库并不是仅仅改动了头文件,所以必须使用我们提供的安装程序进行更新。同时你分发自己程序的时候需要使用更新之后的CRT。你可以认为TR1是VC9的“Service Pack 0”

Q: 如果我使用了TR1,会不会引入对MFC库的依赖?或者,如果我使用了MFC的更新,会不会引入对TR1的依赖?
A: 不会。TR1和MFC的更新是独立的。我们将它们放在一起只是为了方便大家更新。

Q: 你们的TR1实现是否完整?
A: 我们的实现涵盖了TR1中的大部分内容。除了TR1文档中Section 5.2和8中提到的部分(参见 http://open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf),我们没有实现。简而言之,我们实现了TR1中对应boost的部分和无序容器。

Q: 既然TR1实现修改了现有的头文件,那会不会对未使用TR1的代码产生负面影响?
A: 理论上是不会的(如果有影响的话,那就是bug了。如果遇到这种bug,欢迎向我们反馈)
TR1的实现应当既不会影响运行期的行为,也不会产生编译期的警告或者错误(我们力图保证VC的库函数至少能和/W4和平共处)
当然,TR1可能会稍微延长你的编译时间(因为代码变多了)。另外如果你预编译头文件的大小很接近/Zm指定的上限的话,新增的代码可能会导致超过上限。这时候,你可以在你的工程中将_HAS_TR1宏的值设为0,这样TR1的代码就不会参与编译了。

Q: TR1实现会影响编译器或者IDE吗?
A: 不会

Q: 你们是否购买了 Dinkumware的TR1实现的授权?
A: 是的,正如我们也购买了他们的STL库的授权。所以,代码的质量是有保证的

Q: 那么,MS做了哪些工作?
A: 简而言之,我们做了非常多的测试,以及一些针对VC的移植工作
  1. 我们将TR1集成进VC9,使得用户能像使用STL一样方便的使用TR1(为此,我们针对我们的编译系统作了大量枯燥乏味的工作,以便将TR1新增的部分集成进msvcp90.dll。对于安装系统而言,我们需要将新的头文件和源代码集成进Visual Studio的安装包)。这样,用户就不用手工修改自己的包含路径,或者发布新的dll。只需要直接使用我们的安装程序打上补丁,更新一下CRT就可以了。
  2. 我们确保TR1能够在/clr和/clr:pure下正常工作 (这本身已经超出了标准C++的范畴,但是是我们必须要支持的特性)。刚开始的时候,这些选项会导致大量的编译期错误和警告。比如说,内部的一个简单的可变参数的函数调用都会产生"本地代码生成"的警告。消除这些编译错误和警告花了相当长的时间
  3. 我们确保TR1能和编译器的/W4在各种情况下和平共处(包括开了/Za或者/Gz,等等)
  4. 我们确保TR1能和编译器的/analyze选项和平共处。如果可能的话,我们会尽量修改代码,以消除警告。如果实在不行的话,我们会暂时屏蔽警告,不过警告屏蔽仅限于标准头文件,不会影响用户的代码。
  5. 我们发现了一些TR1中的bug,并和Dinkumware一起修复这些bug。Dinkumware的代码非常健壮,但是看得人多了,总能多找到一些bug。我就发现了一些TR1文档本身的bug(Issue 726和Issue 727)
  6. 我们尽量让TR1实现的性能能够比肩boost(这是一个很好的比较对象。当然我们也可以和GCC的TR1实现做对比,不过这样的话还要考虑编译器的差异)。在某些方面,VC9的TR1还比不上boost(希望VC10可以),不过我们已经取得了长足的进步。很感谢MS的性能测试组(这个小组是由Rob Huyett负责的),我们发现了一个regex匹配的性能问题,Dinkumware改进之后,性能提高了4~5倍(注意,beta中没有集成这个fix,所以和boost的实现相比,大约要慢18倍。改进后的实现大约慢3.8倍)。function的性能目前已经和boost差不多了(这个fix也没有集成到beta版中)
    “好吧”, 你可能会问, “regex::optimize可以让匹配更快一些吗?”很不幸,目前还不能。VC9的TR1不支持regex::optimize建议的NFA => DFA的转换,不过我们会在VC10中考虑加入这个功能(根据我个人的测试,boost1.34.1里的regex::optimize什么也没有做)。
  7. 我们选择了部分C++0x中的特性,将其引入TR1。比如,TR1中的shared_ptr并没有提供对allcator的支持,但是对我们的用户而言(包括我们自己的编译器),这个特性很重要。所以我们已经将它集成到最终的发布版本,不过在beta版中还没有提供。
  8. 我们为TR1中的类型编写了调试器自动展开脚本,以便在调试过程中查看它们的内容。因为像STL之类的对象往往很复杂,自动展开特性对调试非常有帮助。TR1类型的自动展开脚本基本上都是我编写的(我个人对实现了share_ptr展开时能在"1 strong ref"和"2 strong refs"之间自由切换感到颇为自豪)。不过,需要注意的是,目前的beta版本尚不包括自动展开脚本
  9. 我们和Dinkumware一起修复了一些VC8 SP1和VC9 RTM中的bug。一个和TR1相关的bug是stdext::hash_set/etc中的。原来的版本中,hash_set的swap函数时间复杂度是O(N),会抛出异常,会导致迭代器失效(因为unordered_set/etc重用了hash_set的实现,所以我们在测试的时候发现了这个bug)。修复之后,时间复杂度降低到O(1),不再会抛出异常,也不会使迭代器失效了。
  10. 因为TR1和STL是紧密结合的,所以我们充分利用这一点以提高性能。比如,我们对存放TR1类型的STL容器(比如vector<shared_ptr<T> >和vector<unordered_set<T> >)做了优化,以避免元素的拷贝。
    我们在VC8和VC9中也针对元素类型是STL容器的STL容器做过类似的优化。这个VC8 STL的特性可能很少有人知道。尽管STL的代码大家都能看到,但是通常没有人会去阅读它的实现(当然,通常也没有这个必要)。这个可以看成是利用库实现的C++0x中的move语义,当然和语言级的支持还是有很大的差距。VC8中,我们使用了一些模板的奇技淫巧,使得诸如vector、deque、list的容器能有O(1)时间复杂度的交换,所以容器的容器实际上是通过交换,而不是先拷贝构造,再析构(当然,对内建类型来说,交换的效率反而要低一些)
    现在我们把这个优化应用到了TR1类型上。所有定制了swap()的TR1类型都将获益,包括:shared_ptr/weak_ptr(避免了引用计数的调整)、 function(避免了内存的动态分配)、regex (避免了拷贝整个有限状态机)、 match_results (避免了拷贝vector)、 unordered_set/etc(避免了拷贝)和array (虽然它本身并不支持O(1)的swap,不过我们调用了它的swap_ranges(),所以如果array的元素有O(1)的swap就可以获得性能的提升)
    也就是说,如果vector<shared_ptr<T> >发生了重新分配(比如由于调用了push_back),share_ptr的引用计数不会先加1然后再减1。我觉得这是个很不错的特性。

如果你还有任何关于扩展功能库的问题,欢迎告诉我们!

此致
Stephan T. Lavavej, Visual C++库函数组程序员

你可能感兴趣的:(C++,Blog,regex,mfc,扩展,编译器)